예제 #1
0
파일: dotproduct.c 프로젝트: abeham/igraph
int igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs,
			    igraph_bool_t directed) {

  igraph_integer_t nrow=igraph_matrix_nrow(vecs);
  igraph_integer_t ncol=igraph_matrix_ncol(vecs);
  int i, j;
  igraph_vector_t edges;
  igraph_bool_t warned_neg=0, warned_big=0;
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
    
  RNG_BEGIN();

  for (i = 0; i < ncol; i++) {
    int from=directed ? 0 : i+1;
    igraph_vector_t v1;
    igraph_vector_view(&v1, &MATRIX(*vecs, 0, i), nrow);
    for (j = from; j < ncol; j++) {
      igraph_real_t prob;
      igraph_vector_t v2;
      if (i==j) { continue; }
      igraph_vector_view(&v2, &MATRIX(*vecs, 0, j), nrow);
      igraph_lapack_ddot(&v1, &v2, &prob);
      if (prob < 0 && ! warned_neg) {
	warned_neg=1;
	IGRAPH_WARNING("Negative connection probability in "
		       "dot-product graph");
      } else if (prob > 1 && ! warned_big) {
	warned_big=1;
	IGRAPH_WARNING("Greater than 1 connection probability in "
		       "dot-product graph");
	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
      } else if (RNG_UNIF01() < prob) { 
	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
      }
    }
  }

  RNG_END();
  
  igraph_create(graph, &edges, ncol, directed);
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);

  return 0;
}
xmlEntityPtr igraph_i_graphml_sax_handler_get_entity(void *state0,
						     const xmlChar* name) {
  xmlEntityPtr predef = xmlGetPredefinedEntity(name);
  if (predef != NULL) return predef;
  IGRAPH_WARNING("unknown XML entity found\n");
  return blankEntity;
}
예제 #3
0
/**
 * \function igraph_lazy_adjedgelist_init
 * Initializes a lazy incidence list of edges
 *
 * This function was superseded by \ref igraph_lazy_inclist_init() in igraph 0.6.
 * Please use \ref igraph_lazy_inclist_init() instead of this function.
 *
 * </para><para>
 * Deprecated in version 0.6.
 */
int igraph_lazy_adjedgelist_init(const igraph_t *graph, 
			                igraph_lazy_inclist_t *il, 
			                igraph_neimode_t mode) {
    IGRAPH_WARNING("igraph_lazy_adjedgelist_init() is deprecated, use "
                   "igraph_lazy_inclist_init() instead");
    return igraph_lazy_inclist_init(graph, il, mode);
}
예제 #4
0
int igraph_i_weighted_cliques(const igraph_t *graph,
                    const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res,
                    igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal)
{
    graph_t *g;
    igraph_integer_t vcount = igraph_vcount(graph);

    if (vcount == 0) {
        igraph_vector_ptr_clear(res);
        return IGRAPH_SUCCESS;
    }

    if (min_weight != (int) min_weight) {
        IGRAPH_WARNING("Only integer vertex weights are supported; the minimum weight will be truncated to its integer part");
        min_weight  = (int) min_weight;
    }

    if (max_weight != (int) max_weight) {
        IGRAPH_WARNING("Only integer vertex weights are supported; the maximum weight will be truncated to its integer part");
        max_weight = (int) max_weight;
    }

    if (min_weight <= 0) min_weight = 1;
    if (max_weight <= 0) max_weight = 0;

    if (max_weight > 0 && max_weight < min_weight)
        IGRAPH_ERROR("max_weight must not be smaller than min_weight", IGRAPH_EINVAL);

    igraph_to_cliquer(graph, &g);
    IGRAPH_FINALLY(graph_free, g);   

    IGRAPH_CHECK(set_weights(vertex_weights, g));

    igraph_vector_ptr_clear(res);
    igraph_cliquer_opt.user_data = res;
    igraph_cliquer_opt.user_function = &collect_cliques_callback;

    IGRAPH_FINALLY(free_clique_list, res);
    CLIQUER_INTERRUPTABLE(clique_find_all(g, min_weight, max_weight, maximal, &igraph_cliquer_opt));
    IGRAPH_FINALLY_CLEAN(1);

    graph_free(g);
    IGRAPH_FINALLY_CLEAN(1);

    return IGRAPH_SUCCESS;
}
예제 #5
0
int igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph,
                                        igraph_vector_ptr_t *res,
                                        igraph_integer_t *clique_number,
                                        igraph_bool_t keep_only_largest,
                                        igraph_bool_t complementer) {
  igraph_i_max_ind_vsets_data_t clqdata;
  long int no_of_nodes = igraph_vcount(graph), i;

  if (igraph_is_directed(graph))
    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");

  clqdata.matrix_size=no_of_nodes;
  clqdata.keep_only_largest=keep_only_largest;

  if (complementer)
    IGRAPH_CHECK(igraph_adjlist_init_complementer(graph, &clqdata.adj_list, IGRAPH_ALL, 0));
  else
    IGRAPH_CHECK(igraph_adjlist_init(graph, &clqdata.adj_list, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list);

  clqdata.IS = igraph_Calloc(no_of_nodes, igraph_integer_t);
  if (clqdata.IS == 0)
    IGRAPH_ERROR("igraph_i_maximal_or_largest_cliques_or_indsets failed", IGRAPH_ENOMEM);
  IGRAPH_FINALLY(igraph_free, clqdata.IS);

  IGRAPH_VECTOR_INIT_FINALLY(&clqdata.deg, no_of_nodes);
  for (i=0; i<no_of_nodes; i++)
    VECTOR(clqdata.deg)[i] = igraph_vector_size(igraph_adjlist_get(&clqdata.adj_list, i));

  clqdata.buckets = igraph_Calloc(no_of_nodes+1, igraph_set_t);
  if (clqdata.buckets == 0)
    IGRAPH_ERROR("igraph_maximal_or_largest_cliques_or_indsets failed", IGRAPH_ENOMEM);
  IGRAPH_FINALLY(igraph_i_free_set_array, clqdata.buckets);

  for (i=0; i<no_of_nodes; i++)
    IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0));

  if (res) igraph_vector_ptr_clear(res);
  
  /* Do the show */
  clqdata.largest_set_size=0;
  IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph, res, &clqdata, 0));

  /* Cleanup */
  for (i=0; i<no_of_nodes; i++) igraph_set_destroy(&clqdata.buckets[i]);
  igraph_adjlist_destroy(&clqdata.adj_list);
  igraph_vector_destroy(&clqdata.deg);
  igraph_free(clqdata.IS);
  igraph_free(clqdata.buckets);
  IGRAPH_FINALLY_CLEAN(4);

  if (clique_number) *clique_number = clqdata.largest_set_size;
  return 0;
}
/* Checks if the community heap satisfies the heap property.
 * Only useful for debugging. */
void igraph_i_fastgreedy_community_list_check_heap(
  igraph_i_fastgreedy_community_list* list) {
  long int i;
  for (i=0; i<list->no_of_communities/2; i++) {
	if ((2*i+1<list->no_of_communities && *list->heap[i]->maxdq->dq < *list->heap[2*i+1]->maxdq->dq) ||
		(2*i+2<list->no_of_communities && *list->heap[i]->maxdq->dq < *list->heap[2*i+2]->maxdq->dq)) {
	  IGRAPH_WARNING("Heap property violated");
	  debug("Position: %ld, %ld and %ld\n", i, 2*i+1, 2*i+2);
	  igraph_i_fastgreedy_community_list_dump_heap(list);
	}
  }
}
예제 #7
0
int igraph_lapack_dgetrf(igraph_matrix_t *a, igraph_vector_int_t *ipiv, 
			 int *info) {
  int m=(int) igraph_matrix_nrow(a);
  int n=(int) igraph_matrix_ncol(a);
  int lda=m > 0 ? m : 1;
  igraph_vector_int_t *myipiv=ipiv, vipiv;

  if (!ipiv) {
    IGRAPH_CHECK(igraph_vector_int_init(&vipiv, m<n ? m : n));
    IGRAPH_FINALLY(igraph_vector_int_destroy, &vipiv);
    myipiv=&vipiv;
  }

  igraphdgetrf_(&m, &n, VECTOR(a->data), &lda, VECTOR(*myipiv), info);

  if (*info > 0) {
    IGRAPH_WARNING("LU: factor is exactly singular");
  } else if (*info < 0) {
    switch(*info) { 
    case -1:
      IGRAPH_ERROR("Invalid number of rows", IGRAPH_ELAPACK);
      break;
    case -2:
      IGRAPH_ERROR("Invalid number of columns", IGRAPH_ELAPACK);
      break;
    case -3:
      IGRAPH_ERROR("Invalid input matrix", IGRAPH_ELAPACK);
      break;
    case -4:
      IGRAPH_ERROR("Invalid LDA parameter", IGRAPH_ELAPACK);
      break;
    case -5:
      IGRAPH_ERROR("Invalid pivot vector", IGRAPH_ELAPACK);
      break;
    case -6:
      IGRAPH_ERROR("Invalid info argument", IGRAPH_ELAPACK);
      break;
    default:
      IGRAPH_ERROR("Unknown LAPACK error", IGRAPH_ELAPACK);
      break;
    }
  }

  if (!ipiv) {
    igraph_vector_int_destroy(&vipiv);
    IGRAPH_FINALLY_CLEAN(1);
  }
  
  return 0;
}
예제 #8
0
파일: bipartite.c 프로젝트: FEYoung/rigraph
int igraph_create_bipartite(igraph_t *graph, const igraph_vector_bool_t *types,
			    const igraph_vector_t *edges, 
			    igraph_bool_t directed) {

  igraph_integer_t no_of_nodes=
    (igraph_integer_t) igraph_vector_bool_size(types);
  long int no_of_edges=igraph_vector_size(edges);
  igraph_real_t min_edge=0, max_edge=0;
  igraph_bool_t min_type=0, max_type=0;
  long int i;

  if (no_of_edges % 2 != 0) {
    IGRAPH_ERROR("Invalid (odd) edges vector", IGRAPH_EINVEVECTOR);
  }
  no_of_edges /= 2;
  
  if (no_of_edges != 0) {
    igraph_vector_minmax(edges, &min_edge, &max_edge);
  }
  if (min_edge < 0 || max_edge >= no_of_nodes) {
    IGRAPH_ERROR("Invalid (negative) vertex id", IGRAPH_EINVVID);
  }

  /* Check types vector */
  if (no_of_nodes != 0) {
    igraph_vector_bool_minmax(types, &min_type, &max_type);
    if (min_type < 0 || max_type > 1) {
      IGRAPH_WARNING("Non-binary type vector when creating a bipartite graph");
    }
  }

  /* Check bipartiteness */
  for (i=0; i<no_of_edges*2; i+=2) {
    long int from=(long int) VECTOR(*edges)[i];
    long int to=(long int) VECTOR(*edges)[i+1];
    long int t1=VECTOR(*types)[from];
    long int t2=VECTOR(*types)[to];
    if ( (t1 && t2) || (!t1 && !t2) ) {
      IGRAPH_ERROR("Invalid edges, not a bipartite graph", IGRAPH_EINVAL);
    }
  }
  
  IGRAPH_CHECK(igraph_empty(graph, no_of_nodes, directed));
  IGRAPH_FINALLY(igraph_destroy, graph);
  IGRAPH_CHECK(igraph_add_edges(graph, edges, 0));
  
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
예제 #9
0
/* Copy weights to a Cliquer graph */
static int set_weights(const igraph_vector_t *vertex_weights, graph_t *g) {
    int i;

    assert(vertex_weights != NULL);

    if (igraph_vector_size(vertex_weights) != g->n)
        IGRAPH_ERROR("Invalid vertex weight vector length", IGRAPH_EINVAL);

    for (i=0; i < g->n; ++i) {
        g->weights[i] = VECTOR(*vertex_weights)[i];
        if (g->weights[i] != VECTOR(*vertex_weights)[i])
            IGRAPH_WARNING("Only integer vertex weights are supported; weights will be truncated to their integer parts");
        if (g->weights[i] <= 0)
            IGRAPH_ERROR("Vertex weights must be positive", IGRAPH_EINVAL);
    }

    return IGRAPH_SUCCESS;
}
예제 #10
0
/* Convert an igraph graph to a Cliquer graph */
static void igraph_to_cliquer(const igraph_t *ig, graph_t **cg) {
    igraph_integer_t vcount, ecount;
    int i;

    if (igraph_is_directed(ig))
      IGRAPH_WARNING("Edge directions are ignored for clique calculations");

    vcount = igraph_vcount(ig);
    ecount = igraph_ecount(ig);

    *cg = graph_new(vcount);

    for (i=0; i < ecount; ++i) {
        long s, t;
        s = IGRAPH_FROM(ig, i);
        t = IGRAPH_TO(ig, i);
        if (s != t)
            GRAPH_ADD_EDGE(*cg, s, t);
    }
}
예제 #11
0
int igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes,
			    igraph_real_t fw_prob, igraph_real_t bw_factor,
			    igraph_integer_t pambs, igraph_bool_t directed) {
  
  igraph_vector_long_t visited;
  long int no_of_nodes=nodes, actnode, i;
  igraph_vector_t edges;
  igraph_vector_t *inneis, *outneis;
  igraph_i_forest_fire_data_t data;
  igraph_dqueue_t neiq;
  long int ambs=pambs;
  igraph_real_t param_geom_out=1-fw_prob;
  igraph_real_t param_geom_in=1-fw_prob*bw_factor;
  
  if (fw_prob < 0) {
    IGRAPH_ERROR("Forest fire model: 'fw_prob' should be between non-negative", 
		 IGRAPH_EINVAL);
  }
  if (bw_factor < 0) {
    IGRAPH_ERROR("Forest fire model: 'bw_factor' should be non-negative",
		 IGRAPH_EINVAL);
  }
  if (ambs < 0) {
    IGRAPH_ERROR("Number of ambassadors ('ambs') should be non-negative",
		 IGRAPH_EINVAL);
  }
  
  if (fw_prob == 0 || ambs == 0) {
    IGRAPH_WARNING("'fw_prob or ambs is zero, creating empty graph");
    IGRAPH_CHECK(igraph_empty(graph, nodes, directed));
    return 0;
  }
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);

  inneis=igraph_Calloc(no_of_nodes, igraph_vector_t);
  if (!inneis) {
    IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, inneis);
  outneis=igraph_Calloc(no_of_nodes, igraph_vector_t);
  if (!outneis) {
    IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, outneis);  
  data.inneis=inneis; 
  data.outneis=outneis;
  data.no_of_nodes=no_of_nodes;
  IGRAPH_FINALLY(igraph_i_forest_fire_free, &data);
  for (i=0; i<no_of_nodes; i++) {
    IGRAPH_CHECK(igraph_vector_init(inneis+i, 0));
    IGRAPH_CHECK(igraph_vector_init(outneis+i, 0));
  }  

  IGRAPH_CHECK(igraph_vector_long_init(&visited, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &visited);
  IGRAPH_DQUEUE_INIT_FINALLY(&neiq, 10);

  RNG_BEGIN();

#define ADD_EDGE_TO(nei) \
      if (VECTOR(visited)[(nei)] != actnode+1) {                     \
	VECTOR(visited)[(nei)] = actnode+1;                          \
	IGRAPH_CHECK(igraph_dqueue_push(&neiq, nei));                \
	IGRAPH_CHECK(igraph_vector_push_back(&edges, actnode));      \
	IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));          \
	IGRAPH_CHECK(igraph_vector_push_back(outneis+actnode, nei)); \
	IGRAPH_CHECK(igraph_vector_push_back(inneis+nei, actnode));  \
      }
  
  IGRAPH_PROGRESS("Forest fire: ", 0.0, NULL);
  
  for (actnode=1; actnode < no_of_nodes; actnode++) {

    IGRAPH_PROGRESS("Forest fire: ", 100.0*actnode/no_of_nodes, NULL);

    IGRAPH_ALLOW_INTERRUPTION();    
    
    /* We don't want to visit the current vertex */
    VECTOR(visited)[actnode] = actnode+1;

    /* Choose ambassador(s) */
    for (i=0; i<ambs; i++) {
      long int a=RNG_INTEGER(0, actnode-1);
      ADD_EDGE_TO(a);
    }
    
    while (!igraph_dqueue_empty(&neiq)) {
      long int actamb=(long int) igraph_dqueue_pop(&neiq);
      igraph_vector_t *outv=outneis+actamb;
      igraph_vector_t *inv=inneis+actamb;
      long int no_in=igraph_vector_size(inv);
      long int no_out=igraph_vector_size(outv);
      long int neis_out=(long int) RNG_GEOM(param_geom_out);
      long int neis_in=(long int) RNG_GEOM(param_geom_in);
      /* outgoing neighbors */
      if (neis_out >= no_out) {
	for (i=0; i<no_out; i++) {
	  long int nei=(long int) VECTOR(*outv)[i];
	  ADD_EDGE_TO(nei);
	}
      } else {
	long int oleft=no_out;
	for (i=0; i<neis_out && oleft > 0; ) {
	  long int which=RNG_INTEGER(0, oleft-1);
	  long int nei=(long int) VECTOR(*outv)[which];
	  VECTOR(*outv)[which] = VECTOR(*outv)[oleft-1];
	  VECTOR(*outv)[oleft-1] = nei;
	  if (VECTOR(visited)[nei] != actnode+1) {
	    ADD_EDGE_TO(nei);
	    i++;
	  }
	  oleft--;
	}
      }
      /* incoming neighbors */
      if (neis_in >= no_in) {
	for (i=0; i<no_in; i++) {
	  long int nei=(long int) VECTOR(*inv)[i];
	  ADD_EDGE_TO(nei);
	}
      } else {
	long int ileft=no_in;
	for (i=0; i<neis_in && ileft > 0; ) {
	  long int which=RNG_INTEGER(0, ileft-1);
	  long int nei=(long int) VECTOR(*inv)[which];
	  VECTOR(*inv)[which] = VECTOR(*inv)[ileft-1];
	  VECTOR(*inv)[ileft-1] = nei;
	  if (VECTOR(visited)[nei] != actnode+1) {
	    ADD_EDGE_TO(nei);
	    i++;
	  }
	  ileft--;
	}
      }
      
    } /* while neiq not empty */

  } /* actnode < no_of_nodes */

#undef ADD_EDGE_TO  

  RNG_END();

  IGRAPH_PROGRESS("Forest fire: ", 100.0, NULL);
  
  igraph_dqueue_destroy(&neiq);
  igraph_vector_long_destroy(&visited);
  igraph_i_forest_fire_free(&data);
  igraph_free(outneis);
  igraph_free(inneis);  
  IGRAPH_FINALLY_CLEAN(5);

  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);

  return 0;
}
예제 #12
0
int igraph_i_kleinberg(const igraph_t *graph, igraph_vector_t *vector,
		       igraph_real_t *value, igraph_bool_t scale,
		       igraph_arpack_options_t *options, int inout) {
  
  igraph_adjlist_t myinadjlist, myoutadjlist;
  igraph_adjlist_t *inadjlist, *outadjlist;
  igraph_vector_t tmp;
  igraph_vector_t values;
  igraph_matrix_t vectors;
  igraph_i_kleinberg_data_t extra;
  long int i;
  
  options->n=igraph_vcount(graph);
  options->start=1;
  
  IGRAPH_VECTOR_INIT_FINALLY(&values, 0);
  IGRAPH_MATRIX_INIT_FINALLY(&vectors, options->n, 1);
  IGRAPH_VECTOR_INIT_FINALLY(&tmp, options->n);
  
  if (inout==0) {
    inadjlist=&myinadjlist; 
    outadjlist=&myoutadjlist;
  } else if (inout==1) {
    inadjlist=&myoutadjlist;
    outadjlist=&myinadjlist;
  } else {
    /* This should not happen */
    IGRAPH_ERROR("Invalid 'inout' argument, plese do not call "
		 "this funtion directly", IGRAPH_FAILURE);
  }

  IGRAPH_CHECK(igraph_adjlist_init(graph, &myinadjlist, IGRAPH_IN));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &myinadjlist);
  IGRAPH_CHECK(igraph_adjlist_init(graph, &myoutadjlist, IGRAPH_OUT));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &myoutadjlist);

  IGRAPH_CHECK(igraph_degree(graph, &tmp, igraph_vss_all(), IGRAPH_ALL, 0));
  for (i=0; i<options->n; i++) {
    if (VECTOR(tmp)[i] != 0) { 
      MATRIX(vectors, i, 0) = VECTOR(tmp)[i];
    } else {
      MATRIX(vectors, i, 0) = 1.0;
    }
  }
	
  extra.in=inadjlist; extra.out=outadjlist; extra.tmp=&tmp;

  options->n = igraph_vcount(graph);
  options->nev = 1;
  options->ncv = 3;
  options->which[0]='L'; options->which[1]='M';
  options->start=1;		/* no random start vector */

  IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_kleinberg2, &extra,
				     options, 0, &values, &vectors));

  igraph_adjlist_destroy(&myoutadjlist);
  igraph_adjlist_destroy(&myinadjlist);
  igraph_vector_destroy(&tmp);
  IGRAPH_FINALLY_CLEAN(3);

  if (value) { 
    *value = VECTOR(values)[0];
  }

  if (vector) {
    igraph_real_t amax=0;
    long int which=0;
    long int i;
    IGRAPH_CHECK(igraph_vector_resize(vector, options->n));
    for (i=0; i<options->n; i++) {
      igraph_real_t tmp;
      VECTOR(*vector)[i] = MATRIX(vectors, i, 0);
      tmp=fabs(VECTOR(*vector)[i]);
      if (tmp>amax) { amax=tmp; which=i; }
    }
    if (scale && amax!=0) { igraph_vector_scale(vector, 1/VECTOR(*vector)[which]); }
  }
  
  if (options->info) {
    IGRAPH_WARNING("Non-zero return code from ARPACK routine!");
  }
  igraph_matrix_destroy(&vectors);
  igraph_vector_destroy(&values);
  IGRAPH_FINALLY_CLEAN(2);
  
  return 0;
}
예제 #13
0
int igraph_pagerank(const igraph_t *graph, igraph_vector_t *vector,
		    igraph_real_t *value, const igraph_vs_t vids,
		    igraph_bool_t directed, igraph_real_t damping, 
		    const igraph_vector_t *weights,
		    igraph_arpack_options_t *options) {

  igraph_matrix_t values;
  igraph_matrix_t vectors;
  igraph_integer_t dirmode;
  igraph_vector_t outdegree;
  igraph_vector_t tmp;
  long int i;
  long int no_of_nodes=igraph_vcount(graph);
  long int no_of_edges=igraph_ecount(graph);

  options->n = igraph_vcount(graph);
  options->nev = 1;
  options->ncv = 3;
  options->which[0]='L'; options->which[1]='M';
  options->start=1;		/* no random start vector */

  directed = directed && igraph_is_directed(graph);

  if (weights && igraph_vector_size(weights) != igraph_ecount(graph))
  {
    IGRAPH_ERROR("Invalid length of weights vector when calculating "
		 "PageRank scores", IGRAPH_EINVAL);
  }
  
  IGRAPH_MATRIX_INIT_FINALLY(&values, 0, 0);
  IGRAPH_MATRIX_INIT_FINALLY(&vectors, options->n, 1);

  if (directed) { dirmode=IGRAPH_IN; } else { dirmode=IGRAPH_ALL; }

  IGRAPH_VECTOR_INIT_FINALLY(&outdegree, options->n);
  IGRAPH_VECTOR_INIT_FINALLY(&tmp, options->n);

  RNG_BEGIN();

  if (!weights) {
    
    igraph_adjlist_t adjlist;
    igraph_i_pagerank_data_t data = { graph, &adjlist, damping,
				      &outdegree, &tmp };

    IGRAPH_CHECK(igraph_degree(graph, &outdegree, igraph_vss_all(),
			       directed ? IGRAPH_OUT : IGRAPH_ALL, /*loops=*/ 0));
    /* Avoid division by zero */
    for (i=0; i<options->n; i++) {
      if (VECTOR(outdegree)[i]==0) {
	VECTOR(outdegree)[i]=1;
      }
      MATRIX(vectors, i, 0) = VECTOR(outdegree)[i];
    } 

    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, dirmode));
    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
    
    IGRAPH_CHECK(igraph_arpack_rnsolve(igraph_i_pagerank,
				       &data, options, 0, &values, &vectors));

    igraph_adjlist_destroy(&adjlist);
    IGRAPH_FINALLY_CLEAN(1);
    
  } else {
    
    igraph_adjedgelist_t adjedgelist;
    igraph_i_pagerank_data2_t data = { graph, &adjedgelist, weights,
				       damping, &outdegree, &tmp };    

    IGRAPH_CHECK(igraph_adjedgelist_init(graph, &adjedgelist, dirmode));
    IGRAPH_FINALLY(igraph_adjedgelist_destroy, &adjedgelist);

    /* Weighted degree */
    for (i=0; i<no_of_edges; i++) {
      long int from=IGRAPH_FROM(graph, i);
      long int to=IGRAPH_TO(graph, i);
      igraph_real_t weight=VECTOR(*weights)[i];
      VECTOR(outdegree)[from] += weight;
      if (!directed) { 
	VECTOR(outdegree)[to]   += weight;
      }
    }
    /* Avoid division by zero */
    for (i=0; i<options->n; i++) {
      if (VECTOR(outdegree)[i]==0) {
	VECTOR(outdegree)[i]=1;
      }
      MATRIX(vectors, i, 0) = VECTOR(outdegree)[i];
    }     
    
    IGRAPH_CHECK(igraph_arpack_rnsolve(igraph_i_pagerank2,
				       &data, options, 0, &values, &vectors));
    
    igraph_adjedgelist_destroy(&adjedgelist);
    IGRAPH_FINALLY_CLEAN(1);
  }

  RNG_END();

  igraph_vector_destroy(&tmp);
  igraph_vector_destroy(&outdegree);
  IGRAPH_FINALLY_CLEAN(2);

  if (value) {
    *value=MATRIX(values, 0, 0);
  }
  
  if (vector) {
    long int i;
    igraph_vit_t vit;
    long int nodes_to_calc;
    igraph_real_t sum=0;
    
    for (i=0; i<no_of_nodes; i++) { 
      sum += MATRIX(vectors, i, 0);
    }

    IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
    nodes_to_calc=IGRAPH_VIT_SIZE(vit);

    IGRAPH_CHECK(igraph_vector_resize(vector, nodes_to_calc));
    for (IGRAPH_VIT_RESET(vit), i=0; !IGRAPH_VIT_END(vit);
	 IGRAPH_VIT_NEXT(vit), i++) {
      VECTOR(*vector)[i] = MATRIX(vectors, (long int)IGRAPH_VIT_GET(vit), 0);
      VECTOR(*vector)[i] /= sum;
    }
    
    igraph_vit_destroy(&vit);
    IGRAPH_FINALLY_CLEAN(1);
  }

  if (options->info) {
    IGRAPH_WARNING("Non-zero return code from ARPACK routine!");
  }
  
  igraph_matrix_destroy(&vectors);
  igraph_matrix_destroy(&values);
  IGRAPH_FINALLY_CLEAN(2);
  return 0;
}
예제 #14
0
igraph_vector_t *igraph_lazy_adjedgelist_get_real(igraph_lazy_adjedgelist_t *il,
						    igraph_integer_t pno) {
    IGRAPH_WARNING("igraph_lazy_adjedgelist_get_real() is deprecated, use "
                   "igraph_lazy_inclist_get_real() instead");
    return igraph_lazy_inclist_get_real(il, pno);
}
예제 #15
0
/**
 * \function igraph_lazy_adjedgelist_destroy
 * Frees all memory allocated for an incidence list.
 *
 * This function was superseded by \ref igraph_lazy_inclist_destroy() in igraph 0.6.
 * Please use \ref igraph_lazy_inclist_destroy() instead of this function.
 *
 * </para><para>
 * Deprecated in version 0.6.
 */
void igraph_lazy_adjedgelist_destroy(igraph_lazy_inclist_t *il) {
    IGRAPH_WARNING("igraph_lazy_adjedgelist_destroy() is deprecated, use "
                   "igraph_lazy_inclist_destroy() instead");
    igraph_lazy_inclist_destroy(il);
}
예제 #16
0
int igraph_eigenvector_centrality(const igraph_t *graph, igraph_vector_t *vector,
				  igraph_real_t *value, igraph_bool_t scale,
				  const igraph_vector_t *weights,
				  igraph_arpack_options_t *options) {
  
  igraph_vector_t values;
  igraph_matrix_t vectors;
  igraph_vector_t degree;
  long int i;
  
  options->n=igraph_vcount(graph);
  options->start=1;		/* no random start vector */

  if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {
    IGRAPH_ERROR("Invalid length of weights vector when calculating "
		 "eigenvector centrality", IGRAPH_EINVAL);
  }

  if (weights && igraph_is_directed(graph)) {
    IGRAPH_WARNING("Weighted directed graph in eigenvector centrality");
  }

  IGRAPH_VECTOR_INIT_FINALLY(&values, 0);
  IGRAPH_MATRIX_INIT_FINALLY(&vectors, options->n, 1);

  IGRAPH_VECTOR_INIT_FINALLY(&degree, options->n);
  IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(), 
			     IGRAPH_ALL, /*loops=*/ 0));
  for (i=0; i<options->n; i++) {
    if (VECTOR(degree)[i]) {
      MATRIX(vectors, i, 0) = VECTOR(degree)[i];
    } else {
      MATRIX(vectors, i, 0) = 1.0;
    }
  }
  igraph_vector_destroy(&degree);
  IGRAPH_FINALLY_CLEAN(1);
  
  options->n = igraph_vcount(graph);
  options->nev = 1;
  options->ncv = 3;
  options->which[0]='L'; options->which[1]='A';
  options->start=1;		/* no random start vector */

  if (!weights) {
    
    igraph_adjlist_t adjlist;

    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
    
    IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_eigenvector_centrality,
				       &adjlist, options, 0, &values, &vectors));

    igraph_adjlist_destroy(&adjlist);
    IGRAPH_FINALLY_CLEAN(1);
    
  } else {
    
    igraph_adjedgelist_t adjedgelist;
    igraph_i_eigenvector_centrality_t data = { graph, &adjedgelist, weights };
    
    IGRAPH_CHECK(igraph_adjedgelist_init(graph, &adjedgelist, IGRAPH_ALL));
    IGRAPH_FINALLY(igraph_adjedgelist_destroy, &adjedgelist);
    
    IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_eigenvector_centrality2,
				       &data, options, 0, &values, &vectors));
    
    igraph_adjedgelist_destroy(&adjedgelist);
    IGRAPH_FINALLY_CLEAN(1);
  }

  if (value) {
    *value=VECTOR(values)[0];
  }
  
  if (vector) {
    igraph_real_t amax=0;
    long int which=0;
    long int i;
    IGRAPH_CHECK(igraph_vector_resize(vector, options->n));
    for (i=0; i<options->n; i++) {
      igraph_real_t tmp;
      VECTOR(*vector)[i] = MATRIX(vectors, i, 0);
      tmp=fabs(VECTOR(*vector)[i]);
      if (tmp>amax) { amax=tmp; which=i; }
    }
    if (scale && amax!=0) { igraph_vector_scale(vector, 1/VECTOR(*vector)[which]); }
  }

  if (options->info) {
    IGRAPH_WARNING("Non-zero return code from ARPACK routine!");
  }
  
  igraph_matrix_destroy(&vectors);
  igraph_vector_destroy(&values);
  IGRAPH_FINALLY_CLEAN(2);
  return 0;
}
void igraph_i_graphml_sax_handler_end_document(void *state0) {
  struct igraph_i_graphml_parser_state *state=
    (struct igraph_i_graphml_parser_state*)state0;
  long i, l;
  int r;
  igraph_i_attribute_record_t idrec, eidrec;
  const char *idstr="id";
  igraph_bool_t already_has_vertex_id=0, already_has_edge_id=0;

  if (!state->successful) return;

  if (state->index<0) {

    igraph_vector_ptr_t vattr, eattr, gattr;
    long int esize=igraph_vector_ptr_size(&state->e_attrs);
    const void **tmp;
    r=igraph_vector_ptr_init(&vattr, 
			     igraph_vector_ptr_size(&state->v_attrs)+1);
    if (r) {
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
      return;
    }
    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vattr);
    if (igraph_strvector_size(&state->edgeids) != 0) {
      esize++;      
    }
    r=igraph_vector_ptr_init(&eattr, esize);
    if (r) {
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
      return;
    }
    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &eattr);
    r=igraph_vector_ptr_init(&gattr, igraph_vector_ptr_size(&state->g_attrs));
    if (r) {
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
      return;
    }
    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &gattr);

    for (i=0; i<igraph_vector_ptr_size(&state->v_attrs); i++) {
      igraph_i_graphml_attribute_record_t *graphmlrec=
	VECTOR(state->v_attrs)[i];
      igraph_i_attribute_record_t *rec=&graphmlrec->record;

      /* Check that the name of the vertex attribute is not 'id'.
	 If it is then we cannot the complimentary 'id' attribute. */
      if (! strcmp(rec->name, idstr)) {
	already_has_vertex_id=1;
      }

      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
	igraph_vector_t *vec=(igraph_vector_t*)rec->value;
	long int origsize=igraph_vector_size(vec);
	long int nodes=igraph_trie_size(&state->node_trie);
	igraph_vector_resize(vec, nodes);
	for (l=origsize; l<nodes; l++) {
	  VECTOR(*vec)[l]=IGRAPH_NAN;
	}
      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
	igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
	long int origsize=igraph_strvector_size(strvec);
	long int nodes=igraph_trie_size(&state->node_trie);
	igraph_strvector_resize(strvec, nodes);
	for (l=origsize; l<nodes; l++) {
	  igraph_strvector_set(strvec, l, "");
	}
      }
      VECTOR(vattr)[i]=rec;
    }
    if (!already_has_vertex_id) {
      idrec.name=idstr;
      idrec.type=IGRAPH_ATTRIBUTE_STRING;
      tmp=&idrec.value;
      igraph_trie_getkeys(&state->node_trie, (const igraph_strvector_t **)tmp);
      VECTOR(vattr)[i]=&idrec;
    } else {
      igraph_vector_ptr_pop_back(&vattr);
      IGRAPH_WARNING("Could not add vertex ids, "
		     "there is already an 'id' vertex attribute");
    }

    for (i=0; i<igraph_vector_ptr_size(&state->e_attrs); i++) {
      igraph_i_graphml_attribute_record_t *graphmlrec=
	VECTOR(state->e_attrs)[i];
      igraph_i_attribute_record_t *rec=&graphmlrec->record;

      if (! strcmp(rec->name, idstr)) {
	already_has_edge_id=1;
      }

      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
	igraph_vector_t *vec=(igraph_vector_t*)rec->value;
	long int origsize=igraph_vector_size(vec);
	long int edges=igraph_vector_size(&state->edgelist)/2;
	igraph_vector_resize(vec, edges);
	for (l=origsize; l<edges; l++) {
	  VECTOR(*vec)[l]=IGRAPH_NAN;
	}
      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
	igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
	long int origsize=igraph_strvector_size(strvec);
	long int edges=igraph_vector_size(&state->edgelist)/2;
	igraph_strvector_resize(strvec, edges);
	for (l=origsize; l<edges; l++) {
	  igraph_strvector_set(strvec, l, "");
	}
      }
      VECTOR(eattr)[i]=rec;
    }
    if (igraph_strvector_size(&state->edgeids) != 0) {
      if (!already_has_edge_id) {
	long int origsize=igraph_strvector_size(&state->edgeids);
	eidrec.name=idstr;
	eidrec.type=IGRAPH_ATTRIBUTE_STRING;
	igraph_strvector_resize(&state->edgeids, 
				igraph_vector_size(&state->edgelist)/2);
	for (; origsize < igraph_strvector_size(&state->edgeids); origsize++) {
	  igraph_strvector_set(&state->edgeids, origsize, "");
	}
	eidrec.value=&state->edgeids;
	VECTOR(eattr)[(long int)igraph_vector_ptr_size(&eattr)-1]=&eidrec;
      } else {
	igraph_vector_ptr_pop_back(&eattr);
	IGRAPH_WARNING("Could not add edge ids, "
		       "there is already an 'id' edge attribute");
      }
    }

    for (i=0; i<igraph_vector_ptr_size(&state->g_attrs); i++) {
      igraph_i_graphml_attribute_record_t *graphmlrec=
	VECTOR(state->g_attrs)[i];
      igraph_i_attribute_record_t *rec=&graphmlrec->record;
      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
	igraph_vector_t *vec=(igraph_vector_t*)rec->value;
	long int origsize=igraph_vector_size(vec);
	igraph_vector_resize(vec, 1);
	for (l=origsize; l<1; l++) {
	  VECTOR(*vec)[l]=IGRAPH_NAN;
	}
      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
	igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
	long int origsize=igraph_strvector_size(strvec);
	igraph_strvector_resize(strvec, 1);
	for (l=origsize; l<1; l++) {
	  igraph_strvector_set(strvec, l, "");
	}
      }
      VECTOR(gattr)[i]=rec;
    }
    
    igraph_empty_attrs(state->g, 0, state->edges_directed, &gattr);
    igraph_add_vertices(state->g, igraph_trie_size(&state->node_trie),
			&vattr);
    igraph_add_edges(state->g, &state->edgelist, &eattr);

    igraph_vector_ptr_destroy(&vattr);
    igraph_vector_ptr_destroy(&eattr);
    igraph_vector_ptr_destroy(&gattr);
    IGRAPH_FINALLY_CLEAN(3);     
  }

  igraph_i_graphml_destroy_state(state);
}
예제 #18
0
int igraph_lapack_dgesv(igraph_matrix_t *a, igraph_vector_int_t *ipiv,
			igraph_matrix_t *b, int *info) {

  int n=(int) igraph_matrix_nrow(a);
  int nrhs=(int) igraph_matrix_ncol(b);
  int lda= n > 0 ? n : 1;
  int ldb= n > 0 ? n : 1;
  igraph_vector_int_t *myipiv=ipiv, vipiv;

  if (n != igraph_matrix_ncol(a)) {
    IGRAPH_ERROR("Cannot LU solve matrix", IGRAPH_NONSQUARE);
  }
  if (n != igraph_matrix_nrow(b)) {
    IGRAPH_ERROR("Cannot LU solve matrix, RHS of wrong size", IGRAPH_EINVAL);
  }

  if (!ipiv) {
    IGRAPH_CHECK(igraph_vector_int_init(&vipiv, n));
    IGRAPH_FINALLY(igraph_vector_int_destroy, &vipiv);
    myipiv=&vipiv;
  }
  
  igraphdgesv_(&n, &nrhs, VECTOR(a->data), &lda, VECTOR(*myipiv),
	       VECTOR(b->data), &ldb, info);

  if (*info > 0) {
    IGRAPH_WARNING("LU: factor is exactly singular");
  } else if (*info < 0) {
    switch(*info) { 
    case -1:
      IGRAPH_ERROR("Invalid number of rows/column", IGRAPH_ELAPACK);
      break;
    case -2:
      IGRAPH_ERROR("Invalid number of RHS vectors", IGRAPH_ELAPACK);
      break;
    case -3:
      IGRAPH_ERROR("Invalid input matrix", IGRAPH_ELAPACK);
      break;
    case -4:
      IGRAPH_ERROR("Invalid LDA parameter", IGRAPH_ELAPACK);
      break;
    case -5:
      IGRAPH_ERROR("Invalid pivot vector", IGRAPH_ELAPACK);
      break;
    case -6:
      IGRAPH_ERROR("Invalid RHS matrix", IGRAPH_ELAPACK);
      break;
    case -7:
      IGRAPH_ERROR("Invalid LDB parameter", IGRAPH_ELAPACK);
      break;
    case -8:
      IGRAPH_ERROR("Invalid info argument", IGRAPH_ELAPACK);
      break;
    default:
      IGRAPH_ERROR("Unknown LAPACK error", IGRAPH_ELAPACK);
      break;
    }
  }
		
  if (!ipiv) {
    igraph_vector_int_destroy(&vipiv);
    IGRAPH_FINALLY_CLEAN(1);
  }
  
  return 0;
}
예제 #19
0
int igraph_i_find_k_cliques(const igraph_t *graph,
			    long int size,
			    const igraph_real_t *member_storage,
			    igraph_real_t **new_member_storage,
			    long int old_clique_count,
			    long int *clique_count,
			    igraph_vector_t *neis,
			    igraph_bool_t independent_vertices) {

  long int j, k, l, m, n, new_member_storage_size;
  const igraph_real_t *c1, *c2;
  igraph_real_t v1, v2;
  igraph_bool_t ok;
  
  /* Allocate the storage */
  *new_member_storage=igraph_Realloc(*new_member_storage, 
			      size*old_clique_count,
			      igraph_real_t);
  if (*new_member_storage == 0) {
    IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
  }
  new_member_storage_size = size*old_clique_count;
  IGRAPH_FINALLY(igraph_free, *new_member_storage);

  m=n=0;
  
  /* Now consider all pairs of i-1-cliques and see if they can be merged */
  for (j=0; j<old_clique_count; j++) {
    for (k=j+1; k<old_clique_count; k++) {
      IGRAPH_ALLOW_INTERRUPTION();
        
      /* Since cliques are represented by their vertex indices in increasing
       * order, two cliques can be merged iff they have exactly the same
       * indices excluding one AND there is an edge between the two different
       * vertices */
      c1 = member_storage+j*(size-1);
      c2 = member_storage+k*(size-1);
      /* Find the longest prefixes of c1 and c2 that are equal */
      for (l=0; l<size-1 && c1[l] == c2[l]; l++)
	(*new_member_storage)[m++]=c1[l];
      /* Now, if l == size-1, the two vectors are totally equal.
	 This is a bug */
      if (l == size-1) {
	IGRAPH_WARNING("possible bug in igraph_cliques");
	m=n;
      } else {
	/* Assuming that j<k, c1[l] is always less than c2[l], since cliques
	 * are ordered alphabetically. Now add c1[l] and store c2[l] in a
	 * dummy variable */
	(*new_member_storage)[m++]=c1[l];
	v1=c1[l];
	v2=c2[l];
	l++;
	/* Copy the remaining part of the two vectors. Every member pair
	 * found in the remaining parts satisfies the following:
	 * 1. If they are equal, they should be added.
	 * 2. If they are not equal, the smaller must be equal to the
	 *    one stored in the dummy variable. If not, the two vectors
	 *    differ in more than one place. The larger will be stored in
	 *    the dummy variable again.
	 */
	ok=1;
	for (; l<size-1; l++) {
	  if (c1[l] == c2[l]) {
	    (*new_member_storage)[m++]=c1[l];
	    ok=0;
	  } else if (ok) {
	    if (c1[l] < c2[l]) {
	      if (c1[l] == v1) {
		(*new_member_storage)[m++]=c1[l];
		v2 = c2[l];
	      } else break;
	    } else {
	      if (ok && c2[l] == v1) {
		(*new_member_storage)[m++]=c2[l];
		v2 = c1[l];
	      } else break;
	    }
	  } else break;
	}
	/* Now, if l != size-1, the two vectors had a difference in more than
	 * one place, so the whole clique is invalid. */
	if (l != size-1) {
	  /* Step back in new_member_storage */
	  m=n;
	} else {
	  /* v1 and v2 are the two different vertices. Check for an edge
	   * if we are looking for cliques and check for the absence of an
	   * edge if we are looking for independent vertex sets */
	  IGRAPH_CHECK(igraph_neighbors(graph, neis, v1, IGRAPH_ALL));
	  l=igraph_vector_search(neis, 0, v2, 0);
	  if ((l && !independent_vertices) || (!l && independent_vertices)) {
	    /* Found a new clique, step forward in new_member_storage */
	    if (m==n || v2>(*new_member_storage)[m-1]) {
	      (*new_member_storage)[m++]=v2;
	      n=m;
	    } else {
	      m=n;
	    }
	  } else {
	    m=n;
	  }
	}
        /* See if new_member_storage is full. If so, reallocate */
        if (m == new_member_storage_size) {
            IGRAPH_FINALLY_CLEAN(1);
            *new_member_storage = igraph_Realloc(*new_member_storage,
                                          new_member_storage_size*2,
                                          igraph_real_t);
            if (*new_member_storage == 0)
                IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
            new_member_storage_size *= 2;
            IGRAPH_FINALLY(igraph_free, *new_member_storage);
        }
      }
    }
  }

  /* Calculate how many cliques have we found */
  *clique_count = n/size;
  
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}  
예제 #20
0
/* Internal function for calculating cliques or independent vertex sets.
 * They are practically the same except that the complementer of the graph
 * should be used in the latter case.
 */
int igraph_i_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,
		     igraph_integer_t min_size, igraph_integer_t max_size,
		     igraph_bool_t independent_vertices) {

  igraph_integer_t no_of_nodes;
  igraph_vector_t neis;
  igraph_real_t *member_storage=0, *new_member_storage, *c1;
  long int i, j, k, clique_count, old_clique_count;
  
  if (igraph_is_directed(graph))
    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");

  no_of_nodes = igraph_vcount(graph);
  
  if (min_size < 0) { min_size = 0; }
  if (max_size > no_of_nodes || max_size <= 0) { max_size = no_of_nodes; }

  igraph_vector_ptr_clear(res);
  
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
  IGRAPH_FINALLY(igraph_i_cliques_free_res, res);
    
  /* Will be resized later, if needed. */
  member_storage=igraph_Calloc(1, igraph_real_t);
  if (member_storage==0) {
    IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, member_storage);
  
  /* Find all 1-cliques: every vertex will be a clique */
  new_member_storage=igraph_Calloc(no_of_nodes, igraph_real_t);
  if (new_member_storage==0) {
    IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, new_member_storage);
  
  for (i=0; i<no_of_nodes; i++) {
    new_member_storage[i] = i;
  }
  clique_count = no_of_nodes;
  old_clique_count = 0;

  /* Add size 1 cliques if requested */
  if (min_size <= 1) {
    IGRAPH_CHECK(igraph_vector_ptr_resize(res, no_of_nodes));
    igraph_vector_ptr_null(res);
    for (i=0; i<no_of_nodes; i++) {
      igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t);
      if (p==0) {
	IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
      }
      IGRAPH_FINALLY(igraph_free, p);
      IGRAPH_CHECK(igraph_vector_init(p, 1));
      VECTOR(*p)[0]=i;
      VECTOR(*res)[i]=p;
      IGRAPH_FINALLY_CLEAN(1);
    }
  }      

  for (i=2; i<=max_size && clique_count > 1; i++) {

    /* Here new_member_storage contains the cliques found in the previous
       iteration. Save this into member_storage, might be needed later  */

    c1=member_storage;
    member_storage=new_member_storage;
    new_member_storage=c1;
    old_clique_count=clique_count;
    
    IGRAPH_ALLOW_INTERRUPTION();
    
    /* Calculate the cliques */
    
    IGRAPH_FINALLY_CLEAN(2);
    IGRAPH_CHECK(igraph_i_find_k_cliques(graph, i, member_storage,
					 &new_member_storage,
					 old_clique_count,
					 &clique_count,
					 &neis,
					 independent_vertices));
    IGRAPH_FINALLY(igraph_free, member_storage);
    IGRAPH_FINALLY(igraph_free, new_member_storage);
    
    /* Add the cliques just found to the result if requested */
    if (i>=min_size && i<=max_size) {
      for (j=0, k=0; j<clique_count; j++, k+=i) {
	igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t);
	if (p==0) {
	  IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM);
	}
	IGRAPH_FINALLY(igraph_free, p);
	IGRAPH_CHECK(igraph_vector_init_copy(p, &new_member_storage[k], i));
	IGRAPH_FINALLY(igraph_vector_destroy, p);
	IGRAPH_CHECK(igraph_vector_ptr_push_back(res, p));
	IGRAPH_FINALLY_CLEAN(2);
      }
    }
    
  } /* i <= max_size && clique_count != 0 */
  
  igraph_free(member_storage);
  igraph_free(new_member_storage);
  igraph_vector_destroy(&neis);
  IGRAPH_FINALLY_CLEAN(4); /* 3 here, +1 is igraph_i_cliques_free_res */
  
  return 0;
}
예제 #21
0
//_________________________________________________________________________
unsigned long graph_molloy_hash::shuffle(unsigned long times, 
					 unsigned long maxtimes, int type) {
  igraph_progress("Shuffle", 0, 0);
  // assert(verify());
  // counters
  unsigned long nb_swaps = 0;
  unsigned long all_swaps = 0;
  unsigned long cost = 0;
  // window
  double T = double(min((unsigned long)(a),times)/10);
  if(type==OPTIMAL_HEURISTICS) T=double(optimal_window());
  if(type==BRUTE_FORCE_HEURISTICS) T=double(times*2);
  // isolation test parameter, and buffers
  double K = 2.4;
  int *Kbuff = new int[int(K)+1];
  bool *visited = new bool[n];
  for(int i=0; i<n; i++) visited[i] = false;
  // Used for monitoring , active only if VERBOSE()
  int failures = 0;
  int successes = 0;
  double avg_K = 0;
  double avg_T = 0;
  unsigned long next = times;
  next=0;
  
  // Shuffle: while #edge swap attempts validated by connectivity < times ...
  while(times>nb_swaps && maxtimes>all_swaps) {
    // Backup graph
    int *save = backup();
    // Prepare counters, K, T
    unsigned long swaps = 0;
    int K_int = 0;
    if(type == FINAL_HEURISTICS || type == BRUTE_FORCE_HEURISTICS) K_int=int(K);
    unsigned long T_int = (unsigned long)(floor(T));
    if(T_int<1) T_int=1;
    // compute cost
    cost += T_int;
    if(K_int>2) cost += (unsigned long)(K_int)*(unsigned long)(T_int);
    // Perform T edge swap attempts
    for(int i=T_int; i>0; i--) {
      // try one swap
      swaps += (unsigned long)(random_edge_swap(K_int, Kbuff, visited));
      all_swaps++;
      // Verbose
      if(nb_swaps+swaps>next) {
        next = (nb_swaps+swaps)+max((unsigned long)(100),(unsigned long)(times/1000));
        int progress = int(double(nb_swaps+swaps) / double(times));
        igraph_progress("Shuffle",  progress, 0);
      }
    }
    // test connectivity
    cost+=(unsigned long)(a/2);
    bool ok = is_connected();
    // performance monitor
    {
      avg_T += double(T_int); avg_K += double(K_int);
      if(ok) successes++; else failures++;
    }
    // restore graph if needed, and count validated swaps
    if(ok) nb_swaps += swaps;
    else {
      restore(save);
      next=nb_swaps;
    }
    delete[] save;
    // Adjust K and T following the heuristics.
    switch(type) {
      int steps;
      case GKAN_HEURISTICS:
        if (ok) T+=1.0; else T*=0.5;
        break;
      case FAB_HEURISTICS:
        steps = 50 / (8+failures+successes);
	if(steps<1) steps=1;
	while(steps--) if(ok) T*=1.17182818; else T*=0.9;
	if(T>double(5*a)) T=double(5*a);
        break;
      case FINAL_HEURISTICS:
        if(ok) { if((K+10.0)*T>5.0*double(a)) K/=1.03; else T*=2; }
	else { K*=1.35; delete[] Kbuff; Kbuff = new int[int(K)+1]; }
	break;
      case OPTIMAL_HEURISTICS:
        if(ok) T=double(optimal_window());
	break;
      case BRUTE_FORCE_HEURISTICS:
        K*=2; delete[] Kbuff; Kbuff = new int[int(K)+1];
	break;
      default:
        IGRAPH_ERROR("Error in graph_molloy_hash::shuffle(): " 
		     "Unknown heuristics type", IGRAPH_EINVAL);
        return 0;
    }
  }

  delete[] Kbuff;
  delete[] visited;

  if (maxtimes <= all_swaps) { 
    IGRAPH_WARNING("Cannot shuffle graph, maybe there is only a single one?");
  }
  
  // Status report
  {
    igraph_status("*** Shuffle Monitor ***\n", 0);
    igraph_statusf(" - Average cost : %f / validated edge swap\n", 0,
		   double(cost)/double(nb_swaps));
    igraph_statusf(" - Connectivity tests : %d (%d successes, %d failures)\n",
		   0, successes + failures, successes, failures);
    igraph_statusf(" - Average window : %d\n", 0, 
		   int(avg_T/double(successes+failures)));
    if(type==FINAL_HEURISTICS || type==BRUTE_FORCE_HEURISTICS)
      igraph_statusf(" - Average isolation test width : %f\n", 0,
		     avg_K/double(successes+failures));
  }
  return nb_swaps;
}
예제 #22
0
int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data) {
  int directed=igraph_is_directed(graph);
  long int i, j, k, l;
  igraph_integer_t no_of_nodes, nodes_to_check, nodes_done;
  igraph_integer_t best_cand = 0, best_cand_degree = 0, best_fini_cand_degree;
  igraph_adjlist_t adj_list;
  igraph_stack_ptr_t stack;
  igraph_i_maximal_cliques_stack_frame frame, *new_frame_ptr;
  igraph_vector_t clique, new_cand, new_fini, cn, best_cand_nbrs, best_fini_cand_nbrs;
  igraph_bool_t cont = 1;
  int assret;

  if (directed)
    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");

  no_of_nodes = igraph_vcount(graph);
  if (no_of_nodes == 0)
    return IGRAPH_SUCCESS;

  /* Construct an adjacency list representation */
  IGRAPH_CHECK(igraph_adjlist_init(graph, &adj_list, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &adj_list);
  IGRAPH_CHECK(igraph_adjlist_simplify(&adj_list));
  igraph_adjlist_sort(&adj_list);

  /* Initialize stack */
  IGRAPH_CHECK(igraph_stack_ptr_init(&stack, 0));
  IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_destroy, &stack);

  /* Create the initial (empty) clique */
  IGRAPH_VECTOR_INIT_FINALLY(&clique, 0);

  /* Initialize new_cand, new_fini, cn, best_cand_nbrs and best_fini_cand_nbrs (will be used later) */
  IGRAPH_VECTOR_INIT_FINALLY(&new_cand, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&new_fini, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&cn, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&best_cand_nbrs, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&best_fini_cand_nbrs, 0);

  /* Find the vertex with the highest degree */
  best_cand = 0; best_cand_degree = igraph_vector_size(igraph_adjlist_get(&adj_list, 0));
  for (i = 1; i < no_of_nodes; i++) {
    j = igraph_vector_size(igraph_adjlist_get(&adj_list, i));
    if (j > best_cand_degree) {
      best_cand = i;
      best_cand_degree = j;
    }
  }

  /* Create the initial stack frame */
  IGRAPH_CHECK(igraph_vector_init_seq(&frame.cand, 0, no_of_nodes-1));
  IGRAPH_FINALLY(igraph_vector_destroy, &frame.cand);
  IGRAPH_CHECK(igraph_vector_init(&frame.fini, 0));
  IGRAPH_FINALLY(igraph_vector_destroy, &frame.fini);
  IGRAPH_CHECK(igraph_vector_init(&frame.cand_filtered, 0));
  IGRAPH_FINALLY(igraph_vector_destroy, &frame.cand_filtered);
  IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand,
        igraph_adjlist_get(&adj_list, best_cand), &frame.cand_filtered));
  IGRAPH_FINALLY_CLEAN(3);
  IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_frame_destroy, &frame);

  /* TODO: frame.cand and frame.fini should be a set instead of a vector */

  /* Main loop starts here */
  nodes_to_check = igraph_vector_size(&frame.cand_filtered); nodes_done = 0;
  while (!igraph_vector_empty(&frame.cand_filtered) || !igraph_stack_ptr_empty(&stack)) {
    if (igraph_vector_empty(&frame.cand_filtered)) {
      /* No candidates left to check in this stack frame, pop out the previous stack frame */
      igraph_i_maximal_cliques_stack_frame *newframe = igraph_stack_ptr_pop(&stack);
      igraph_i_maximal_cliques_stack_frame_destroy(&frame);
      frame = *newframe;
      free(newframe);

      if (igraph_stack_ptr_size(&stack) == 1) {
        /* We will be using the next candidate node in the next iteration, so we can increase
         * nodes_done by 1 */
        nodes_done++;
      }

      /* For efficiency reasons, we only check for interruption and show progress here */
      IGRAPH_PROGRESS("Maximal cliques: ", 100.0 * nodes_done / nodes_to_check, NULL);
      IGRAPH_ALLOW_INTERRUPTION();

      igraph_vector_pop_back(&clique);
      continue;
    }

    /* Try the next node in the clique */
    i = igraph_vector_pop_back(&frame.cand_filtered);
    IGRAPH_CHECK(igraph_vector_push_back(&clique, i));

    /* Remove the node from the candidate list */
    assret=igraph_vector_binsearch(&frame.cand, i, &j); assert(assret);
    igraph_vector_remove(&frame.cand, j);

    /* Add the node to the finished list */
    assret = !igraph_vector_binsearch(&frame.fini, i, &j); assert(assret);
    IGRAPH_CHECK(igraph_vector_insert(&frame.fini, j, i));

    /* Create new_cand and new_fini */
    IGRAPH_CHECK(igraph_vector_intersect_sorted(&frame.cand, igraph_adjlist_get(&adj_list, i), &new_cand));
    IGRAPH_CHECK(igraph_vector_intersect_sorted(&frame.fini, igraph_adjlist_get(&adj_list, i), &new_fini));

    /* Do we have anything more to search? */
    if (igraph_vector_empty(&new_cand)) {
      if (igraph_vector_empty(&new_fini)) {
        /* We have a maximal clique here */
        IGRAPH_CHECK(func(&clique, data, &cont));
        if (!cont) {
          /* The callback function requested to stop the search */
          break;
        }
      }
      igraph_vector_pop_back(&clique);
      continue;
    }
    if (igraph_vector_empty(&new_fini) && igraph_vector_size(&new_cand) == 1) {
      /* Shortcut: only one node left */
      IGRAPH_CHECK(igraph_vector_push_back(&clique, VECTOR(new_cand)[0]));
      IGRAPH_CHECK(func(&clique, data, &cont));
      if (!cont) {
        /* The callback function requested to stop the search */
        break;
      }
      igraph_vector_pop_back(&clique);
      igraph_vector_pop_back(&clique);
      continue;
    }

    /* Find the next best candidate node in new_fini */
    l = igraph_vector_size(&new_cand);
    best_cand_degree = -1;
    j = igraph_vector_size(&new_fini);
    for (i = 0; i < j; i++) {
      k = (long int)VECTOR(new_fini)[i];
      IGRAPH_CHECK(igraph_vector_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn));
      if (igraph_vector_size(&cn) > best_cand_degree) {
        best_cand_degree = igraph_vector_size(&cn);
        IGRAPH_CHECK(igraph_vector_update(&best_fini_cand_nbrs, &cn));
        if (best_cand_degree == l) {
          /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */
          break;
        }
      }
    }
    /* Shortcut here: we don't have to examine new_cand */
    if (best_cand_degree == l) {
      igraph_vector_pop_back(&clique);
      continue;
    }
    /* Still finding best candidate node */
    best_fini_cand_degree = best_cand_degree;
    best_cand_degree = -1;
    j = igraph_vector_size(&new_cand);
    l = l - 1;
    for (i = 0; i < j; i++) {
      k = (long int)VECTOR(new_cand)[i];
      IGRAPH_CHECK(igraph_vector_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn));
      if (igraph_vector_size(&cn) > best_cand_degree) {
        best_cand_degree = igraph_vector_size(&cn);
        IGRAPH_CHECK(igraph_vector_update(&best_cand_nbrs, &cn));
        if (best_cand_degree == l) {
          /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */
          break;
        }
      }
    }

    /* Create a new stack frame in case we back out later */
    new_frame_ptr = igraph_Calloc(1, igraph_i_maximal_cliques_stack_frame);
    if (new_frame_ptr == 0) {
      IGRAPH_ERROR("cannot allocate new stack frame", IGRAPH_ENOMEM);
    }
    IGRAPH_FINALLY(igraph_free, new_frame_ptr);
    *new_frame_ptr = frame;
    memset(&frame, 0, sizeof(frame));
    IGRAPH_CHECK(igraph_stack_ptr_push(&stack, new_frame_ptr));
    IGRAPH_FINALLY_CLEAN(1);  /* ownership of new_frame_ptr taken by the stack */
    /* Ownership of the current frame and its vectors (frame.cand, frame.done, frame.cand_filtered)
     * is taken by the stack from now on. Vectors in frame must be re-initialized with new_cand,
     * new_fini and stuff. The old frame.cand and frame.fini won't be leaked because they are
     * managed by the stack now. */
    frame.cand = new_cand;
    frame.fini = new_fini;
    IGRAPH_CHECK(igraph_vector_init(&new_cand, 0));
    IGRAPH_CHECK(igraph_vector_init(&new_fini, 0));
    IGRAPH_CHECK(igraph_vector_init(&frame.cand_filtered, 0));

    /* Adjust frame.cand_filtered */
    if (best_cand_degree < best_fini_cand_degree) {
      IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, &best_fini_cand_nbrs, &frame.cand_filtered));
    } else {
      IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, &best_cand_nbrs, &frame.cand_filtered));
    }
  }

  IGRAPH_PROGRESS("Maximal cliques: ", 100.0, NULL);

  igraph_adjlist_destroy(&adj_list);
  igraph_vector_destroy(&clique);
  igraph_vector_destroy(&new_cand);
  igraph_vector_destroy(&new_fini);
  igraph_vector_destroy(&cn);
  igraph_vector_destroy(&best_cand_nbrs);
  igraph_vector_destroy(&best_fini_cand_nbrs);
  igraph_i_maximal_cliques_stack_frame_destroy(&frame);
  igraph_i_maximal_cliques_stack_destroy(&stack);
  IGRAPH_FINALLY_CLEAN(9);

  return IGRAPH_SUCCESS;
}
예제 #23
0
int igraph_adjedgelist_remove_duplicate(const igraph_t *graph, 
					igraph_inclist_t *al) {
    IGRAPH_WARNING("igraph_adjedgelist_remove_duplicate() is deprecated, use "
                   "igraph_inclist_remove_duplicate() instead");
    return igraph_inclist_remove_duplicate(graph, al);
}
예제 #24
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;
}
예제 #25
0
int igraph_adjedgelist_print(const igraph_inclist_t *al, FILE *outfile) {
    IGRAPH_WARNING("igraph_adjedgelist_print() is deprecated, use "
                   "igraph_inclist_print() instead");
    return igraph_inclist_print(al, outfile);
}
예제 #26
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;
}
예제 #27
0
/**
 * Finding maximum bipartite matchings on bipartite graphs using the
 * Hungarian algorithm (a.k.a. Kuhn-Munkres algorithm).
 *
 * The algorithm uses a maximum cardinality matching on a subset of
 * tight edges as a starting point. This is achieved by
 * \c igraph_i_maximum_bipartite_matching_unweighted on the restricted
 * graph.
 *
 * The algorithm works reliably only if the weights are integers. The
 * \c eps parameter should specity a very small number; if the slack on
 * an edge falls below \c eps, it will be considered tight. If all your
 * weights are integers, you can safely set \c eps to zero.
 */
int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
    const igraph_vector_t* weights, igraph_real_t eps) {
  long int i, j, k, n, no_of_nodes, no_of_edges;
  igraph_integer_t u, v, w, msize;
  igraph_t newgraph;
  igraph_vector_long_t match;       /* will store the matching */
  igraph_vector_t slack;            /* will store the slack on each edge */
  igraph_vector_t parent;           /* parent vertices during a BFS */
  igraph_vector_t vec1, vec2;       /* general temporary vectors */
  igraph_vector_t labels;           /* will store the labels */
  igraph_dqueue_long_t q;           /* a FIFO for BST */
  igraph_bool_t smaller_set;        /* denotes which part of the bipartite graph is smaller */
  long int smaller_set_size;        /* size of the smaller set */
  igraph_real_t dual;               /* solution of the dual problem */
  igraph_adjlist_t tight_phantom_edges; /* adjacency list to manage tight phantom edges */
  igraph_integer_t alternating_path_endpoint;
  igraph_vector_t* neis;
  igraph_vector_int_t *neis2;
  igraph_inclist_t inclist;         /* incidence list of the original graph */ 

  /* The Hungarian algorithm is originally for complete bipartite graphs.
   * For non-complete bipartite graphs, a phantom edge of weight zero must be
   * added between every pair of non-connected vertices. We don't do this
   * explicitly of course. See the comments below about how phantom edges
   * are taken into account. */

  no_of_nodes = igraph_vcount(graph);
  no_of_edges = igraph_ecount(graph);
  if (eps < 0) {
    IGRAPH_WARNING("negative epsilon given, clamping to zero");
    eps = 0;
  }

  /* (1) Initialize data structures */
  IGRAPH_CHECK(igraph_vector_long_init(&match, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &match);
  IGRAPH_CHECK(igraph_vector_init(&slack, no_of_edges));
  IGRAPH_FINALLY(igraph_vector_destroy, &slack);
  IGRAPH_VECTOR_INIT_FINALLY(&vec1, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&vec2, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&labels, no_of_nodes);
  IGRAPH_CHECK(igraph_dqueue_long_init(&q, 0));
  IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q);
  IGRAPH_VECTOR_INIT_FINALLY(&parent, no_of_nodes);
  IGRAPH_CHECK(igraph_adjlist_init_empty(&tight_phantom_edges, 
					 (igraph_integer_t) no_of_nodes));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &tight_phantom_edges);
  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);

  /* (2) Find which set is the smaller one */
  j = 0;
  for (i = 0; i < no_of_nodes; i++) {
    if (VECTOR(*types)[i] == 0)
      j++;
  }
  smaller_set = (j > no_of_nodes / 2);
  smaller_set_size = smaller_set ? (no_of_nodes - j) : j;

  /* (3) Calculate the initial labeling and the set of tight edges. Use the
   *     smaller set only. Here we can assume that there are no phantom edges
   *     among the tight ones. */
  dual = 0;
  for (i = 0; i < no_of_nodes; i++) {
    igraph_real_t max_weight = 0;

    if (VECTOR(*types)[i] != smaller_set) {
      VECTOR(labels)[i] = 0;
      continue;
    }

    neis = igraph_inclist_get(&inclist, i);
    n = igraph_vector_size(neis);
    for (j = 0, k = 0; j < n; j++) {
      if (VECTOR(*weights)[(long int)VECTOR(*neis)[j]] > max_weight) {
        k = (long int) VECTOR(*neis)[j];
        max_weight = VECTOR(*weights)[k];
      }
    }

    VECTOR(labels)[i] = max_weight;
    dual += max_weight;
  }

  igraph_vector_clear(&vec1);
  IGRAPH_CHECK(igraph_get_edgelist(graph, &vec2, 0));
#define IS_TIGHT(i) (VECTOR(slack)[i] <= eps)
  for (i = 0, j = 0; i < no_of_edges; i++, j+=2) {
    u = (igraph_integer_t) VECTOR(vec2)[j];
    v = (igraph_integer_t) VECTOR(vec2)[j+1];
    VECTOR(slack)[i] = VECTOR(labels)[u] + VECTOR(labels)[v] - VECTOR(*weights)[i];
    if (IS_TIGHT(i)) {
      IGRAPH_CHECK(igraph_vector_push_back(&vec1, u));
      IGRAPH_CHECK(igraph_vector_push_back(&vec1, v));
    }
  }
  igraph_vector_clear(&vec2);

  /* (4) Construct a temporary graph on which the initial maximum matching
   *     will be calculated (only on the subset of tight edges) */
  IGRAPH_CHECK(igraph_create(&newgraph, &vec1,
			     (igraph_integer_t) no_of_nodes, 0));
  IGRAPH_FINALLY(igraph_destroy, &newgraph);
  IGRAPH_CHECK(igraph_maximum_bipartite_matching(&newgraph, types, &msize, 0, &match, 0, 0));
  igraph_destroy(&newgraph);
  IGRAPH_FINALLY_CLEAN(1);

  /* (5) Main loop until the matching becomes maximal */
  while (msize < smaller_set_size) {
    igraph_real_t min_slack, min_slack_2;
    igraph_integer_t min_slack_u, min_slack_v;

    /* (7) Fill the push queue with the unmatched nodes from the smaller set. */
    igraph_vector_clear(&vec1);
    igraph_vector_clear(&vec2);
    igraph_vector_fill(&parent, -1);
    for (i = 0; i < no_of_nodes; i++) {
      if (UNMATCHED(i) && VECTOR(*types)[i] == smaller_set) {
        IGRAPH_CHECK(igraph_dqueue_long_push(&q, i));
        VECTOR(parent)[i] = i;
        IGRAPH_CHECK(igraph_vector_push_back(&vec1, i));
      }
    }

#ifdef MATCHING_DEBUG
    debug("Matching:");
    igraph_vector_long_print(&match);
    debug("Unmatched vertices are marked by non-negative numbers:\n");
    igraph_vector_print(&parent);
    debug("Labeling:");
    igraph_vector_print(&labels);
    debug("Slacks:");
    igraph_vector_print(&slack);
#endif

    /* (8) Run the BFS */
    alternating_path_endpoint = -1;
    while (!igraph_dqueue_long_empty(&q)) {
      v = (int) igraph_dqueue_long_pop(&q);

      debug("Considering vertex %ld\n", (long int)v);

      /* v is always in the smaller set. Find the neighbors of v, which
       * are all in the larger set. Find the pairs of these nodes in
       * the smaller set and push them to the queue. Mark the traversed
       * nodes as seen.
       *
       * Here we have to be careful as there are two types of incident
       * edges on v: real edges and phantom ones. Real edges are
       * given by igraph_inclist_get. Phantom edges are not given so we
       * (ab)use an adjacency list data structure that lists the
       * vertices connected to v by phantom edges only. */
      neis = igraph_inclist_get(&inclist, v);
      n = igraph_vector_size(neis);
      for (i = 0; i < n; i++) {
        j = (long int) VECTOR(*neis)[i];
        /* We only care about tight edges */
        if (!IS_TIGHT(j))
          continue;
        /* Have we seen the other endpoint already? */
        u = IGRAPH_OTHER(graph, j, v);
        if (VECTOR(parent)[u] >= 0)
          continue;
        debug("  Reached vertex %ld via edge %ld\n", (long)u, (long)j);
        VECTOR(parent)[u] = v;
        IGRAPH_CHECK(igraph_vector_push_back(&vec2, u));
        w = (int) VECTOR(match)[u];
        if (w == -1) {
          /* u is unmatched and it is in the larger set. Therefore, we
           * could improve the matching by following the parents back
           * from u to the root.
           */
          alternating_path_endpoint = u;
          break;  /* since we don't need any more endpoints that come from v */
        } else {
          IGRAPH_CHECK(igraph_dqueue_long_push(&q, w));
          VECTOR(parent)[w] = u;
        }
        IGRAPH_CHECK(igraph_vector_push_back(&vec1, w));
      }

      /* Now do the same with the phantom edges */
      neis2 = igraph_adjlist_get(&tight_phantom_edges, v);
      n = igraph_vector_int_size(neis2);
      for (i = 0; i < n; i++) {
        u = (igraph_integer_t) VECTOR(*neis2)[i];
        /* Have we seen u already? */
        if (VECTOR(parent)[u] >= 0)
          continue;
        /* Check if the edge is really tight; it might have happened that the
         * edge became non-tight in the meanwhile. We do not remove these from
         * tight_phantom_edges at the moment, so we check them once again here.
         */
        if (fabs(VECTOR(labels)[(long int)v] + VECTOR(labels)[(long int)u]) > eps)
          continue;
        debug("  Reached vertex %ld via tight phantom edge\n", (long)u);
        VECTOR(parent)[u] = v;
        IGRAPH_CHECK(igraph_vector_push_back(&vec2, u));
        w = (int) VECTOR(match)[u];
        if (w == -1) {
          /* u is unmatched and it is in the larger set. Therefore, we
           * could improve the matching by following the parents back
           * from u to the root.
           */
          alternating_path_endpoint = u;
          break;  /* since we don't need any more endpoints that come from v */
        } else {
          IGRAPH_CHECK(igraph_dqueue_long_push(&q, w));
          VECTOR(parent)[w] = u;
        }
        IGRAPH_CHECK(igraph_vector_push_back(&vec1, w));
      }
    }

    /* Okay; did we have an alternating path? */
    if (alternating_path_endpoint != -1) {
#ifdef MATCHING_DEBUG
      debug("BFS parent tree:");
      igraph_vector_print(&parent);
#endif
      /* Increase the size of the matching with the alternating path. */
      v = alternating_path_endpoint;
      u = (igraph_integer_t) VECTOR(parent)[v];
      debug("Extending matching with alternating path ending in %ld.\n", (long int)v);

      while (u != v) {
        w = (int) VECTOR(match)[v];
        if (w != -1)
          VECTOR(match)[w] = -1;
        VECTOR(match)[v] = u;

        VECTOR(match)[v] = u;
        w = (int) VECTOR(match)[u];
        if (w != -1)
          VECTOR(match)[w] = -1;
        VECTOR(match)[u] = v;

        v = (igraph_integer_t) VECTOR(parent)[u];
	u = (igraph_integer_t) VECTOR(parent)[v];
      }

      msize++;

#ifdef MATCHING_DEBUG
      debug("New matching after update:");
      igraph_vector_long_print(&match);
      debug("Matching size is now: %ld\n", (long)msize);
#endif
      continue;
    }

#ifdef MATCHING_DEBUG
    debug("Vertices reachable from unmatched ones via tight edges:\n");
    igraph_vector_print(&vec1);
    igraph_vector_print(&vec2);
#endif

    /* At this point, vec1 contains the nodes in the smaller set (A)
     * reachable from unmatched nodes in A via tight edges only, while vec2
     * contains the nodes in the larger set (B) reachable from unmatched
     * nodes in A via tight edges only. Also, parent[i] >= 0 if node i
     * is reachable */

    /* Check the edges between reachable nodes in A and unreachable
     * nodes in B, and find the minimum slack on them.
     *
     * Since the weights are positive, we do no harm if we first
     * assume that there are no "real" edges between the two sets
     * mentioned above and determine an upper bound for min_slack
     * based on this. */
    min_slack = IGRAPH_INFINITY;
    min_slack_u = min_slack_v = 0;
    n = igraph_vector_size(&vec1);
    for (i = 0; i < no_of_nodes; i++) {
      if (VECTOR(*types)[i] == smaller_set)
        continue;
      if (VECTOR(labels)[i] < min_slack) {
        min_slack = VECTOR(labels)[i];
        min_slack_v = (igraph_integer_t) i;
      }
    }
    min_slack_2 = IGRAPH_INFINITY;
    for (i = 0; i < n; i++) {
      u = (igraph_integer_t) VECTOR(vec1)[i];
      /* u is surely from the smaller set, but we are interested in it
       * only if it is reachable from an unmatched vertex */
      if (VECTOR(parent)[u] < 0)
        continue;
      if (VECTOR(labels)[u] < min_slack_2) {
        min_slack_2 = VECTOR(labels)[u];
        min_slack_u = u;
      }
    }
    min_slack += min_slack_2;
    debug("Starting approximation for min_slack = %.4f (based on vertex pair %ld--%ld)\n",
        min_slack, (long int)min_slack_u, (long int)min_slack_v);

    n = igraph_vector_size(&vec1);
    for (i = 0; i < n; i++) {
      u = (igraph_integer_t) VECTOR(vec1)[i];
      /* u is a reachable node in A; get its incident edges.
       *
       * There are two types of incident edges: 1) real edges,
       * 2) phantom edges. Phantom edges were treated earlier
       * when we determined the initial value for min_slack. */
      debug("Trying to expand along vertex %ld\n", (long int)u);
      neis = igraph_inclist_get(&inclist, u);
      k = igraph_vector_size(neis);
      for (j = 0; j < k; j++) {
        /* v is the vertex sitting at the other end of an edge incident
         * on u; check whether it was reached */
        v = IGRAPH_OTHER(graph, VECTOR(*neis)[j], u);
        debug("  Edge %ld -- %ld (ID=%ld)\n", (long int)u, (long int)v, (long int)VECTOR(*neis)[j]);
        if (VECTOR(parent)[v] >= 0) {
          /* v was reached, so we are not interested in it */
          debug("    %ld was reached, so we are not interested in it\n", (long int)v);
          continue;
        }
        /* v is the ID of the edge from now on */
        v = (igraph_integer_t) VECTOR(*neis)[j];
        if (VECTOR(slack)[v] < min_slack) {
          min_slack = VECTOR(slack)[v];
          min_slack_u = u;
          min_slack_v = IGRAPH_OTHER(graph, v, u);
        }
        debug("    Slack of this edge: %.4f, min slack is now: %.4f\n",
            VECTOR(slack)[v], min_slack);
      }
    }
    debug("Minimum slack: %.4f on edge %d--%d\n", min_slack, (int)min_slack_u, (int)min_slack_v);

    if (min_slack > 0) {
      /* Decrease the label of reachable nodes in A by min_slack.
       * Also update the dual solution */
      n = igraph_vector_size(&vec1);
      for (i = 0; i < n; i++) {
        u = (igraph_integer_t) VECTOR(vec1)[i];
        VECTOR(labels)[u] -= min_slack;
        neis = igraph_inclist_get(&inclist, u);
        k = igraph_vector_size(neis);
        for (j = 0; j < k; j++) {
          debug("  Decreasing slack of edge %ld (%ld--%ld) by %.4f\n",
              (long)VECTOR(*neis)[j], (long)u,
              (long)IGRAPH_OTHER(graph, VECTOR(*neis)[j], u), min_slack);
          VECTOR(slack)[(long int)VECTOR(*neis)[j]] -= min_slack;
        }
        dual -= min_slack;
      }

      /* Increase the label of reachable nodes in B by min_slack.
       * Also update the dual solution */
      n = igraph_vector_size(&vec2);
      for (i = 0; i < n; i++) {
        u = (igraph_integer_t) VECTOR(vec2)[i];
        VECTOR(labels)[u] += min_slack;
        neis = igraph_inclist_get(&inclist, u);
        k = igraph_vector_size(neis);
        for (j = 0; j < k; j++) {
          debug("  Increasing slack of edge %ld (%ld--%ld) by %.4f\n",
              (long)VECTOR(*neis)[j], (long)u,
              (long)IGRAPH_OTHER(graph, (long)VECTOR(*neis)[j], u), min_slack);
          VECTOR(slack)[(long int)VECTOR(*neis)[j]] += min_slack;
        }
        dual += min_slack;
      }
    }

    /* Update the set of tight phantom edges.
     * Note that we must do it even if min_slack is zero; the reason is that
     * it can happen that min_slack is zero in the first step if there are
     * isolated nodes in the input graph.
     *
     * TODO: this is O(n^2) here. Can we do it faster? */
    for (u = 0; u < no_of_nodes; u++) {
      if (VECTOR(*types)[u] != smaller_set)
        continue;

      for (v = 0; v < no_of_nodes; v++) {
        if (VECTOR(*types)[v] == smaller_set)
          continue;

        if (VECTOR(labels)[(long int)u] + VECTOR(labels)[(long int)v] <= eps) {
          /* Tight phantom edge found. Note that we don't have to check whether
           * u and v are connected; if they were, then the slack of this edge
           * would be negative. */
          neis2 = igraph_adjlist_get(&tight_phantom_edges, u);
          if (!igraph_vector_int_binsearch(neis2, v, &i)) {
            debug("New tight phantom edge: %ld -- %ld\n", (long)u, (long)v);
            IGRAPH_CHECK(igraph_vector_int_insert(neis2, i, v));
          }
        }
      }
    }

#ifdef MATCHING_DEBUG
    debug("New labels:");
    igraph_vector_print(&labels);
    debug("Slacks after updating with min_slack:");
    igraph_vector_print(&slack);
#endif
  }

  /* Cleanup: remove phantom edges from the matching */
  for (i = 0; i < no_of_nodes; i++) {
    if (VECTOR(*types)[i] != smaller_set)
      continue;

    if (VECTOR(match)[i] != -1) {
      j = VECTOR(match)[i];
      neis2 = igraph_adjlist_get(&tight_phantom_edges, i);
      if (igraph_vector_int_binsearch(neis2, j, 0)) {
        VECTOR(match)[i] = VECTOR(match)[j] = -1;
        msize--;
      }
    }
  }

  /* Fill the output parameters */
  if (matching != 0) {
    IGRAPH_CHECK(igraph_vector_long_update(matching, &match));
  }
  if (matching_size != 0) {
    *matching_size = msize;
  }
  if (matching_weight != 0) {
    *matching_weight = 0;
    for (i = 0; i < no_of_edges; i++) {
      if (IS_TIGHT(i)) {
        IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) i, &u, &v));
        if (VECTOR(match)[u] == v)
          *matching_weight += VECTOR(*weights)[i];
      }
    }
  }

  /* Release everything */
#undef IS_TIGHT
  igraph_inclist_destroy(&inclist);
  igraph_adjlist_destroy(&tight_phantom_edges);
  igraph_vector_destroy(&parent);
  igraph_dqueue_long_destroy(&q);
  igraph_vector_destroy(&labels);
  igraph_vector_destroy(&vec1);
  igraph_vector_destroy(&vec2);
  igraph_vector_destroy(&slack);
  igraph_vector_long_destroy(&match);
  IGRAPH_FINALLY_CLEAN(9);

  return IGRAPH_SUCCESS;
}