コード例 #1
0
ファイル: operators.c プロジェクト: GennadyKharlam/igraph
int igraph_complementer(igraph_t *res, const igraph_t *graph, 
			igraph_bool_t loops) {

  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_t edges;
  igraph_vector_t neis;
  long int i, j;
  long int zero=0, *limit;

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);

  if (igraph_is_directed(graph)) {
    limit=&zero;
  } else {
    limit=&i;
  }
  
  for (i=0; i<no_of_nodes; i++) {
    IGRAPH_ALLOW_INTERRUPTION();
    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, 
				  IGRAPH_OUT));
    if (loops) {
      for (j=no_of_nodes-1; j>=*limit; j--) {
	if (igraph_vector_empty(&neis) || j>igraph_vector_tail(&neis)) {
	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	  IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
	} else {
	  igraph_vector_pop_back(&neis);
	}
      }
    } else {
      for (j=no_of_nodes-1; j>=*limit; j--) {
	if (igraph_vector_empty(&neis) || j>igraph_vector_tail(&neis)) {
	  if (i!=j) {
	    IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	    IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
	  }
	} else {
	  igraph_vector_pop_back(&neis);
	}
      }
    }      
  }
  
  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, 
			     igraph_is_directed(graph)));  
  igraph_vector_destroy(&edges);
  igraph_vector_destroy(&neis);
  IGRAPH_I_ATTRIBUTE_DESTROY(res);
  IGRAPH_I_ATTRIBUTE_COPY(res, graph, /*graph=*/1, /*vertex=*/1, /*edge=*/0);
  IGRAPH_FINALLY_CLEAN(2);
  return 0;
}
コード例 #2
0
int igraph_copy(igraph_t *to, const igraph_t *from) {
  to->n=from->n;
  to->directed=from->directed;
  IGRAPH_CHECK(igraph_vector_copy(&to->from, &from->from));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->from);
  IGRAPH_CHECK(igraph_vector_copy(&to->to, &from->to));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->to);
  IGRAPH_CHECK(igraph_vector_copy(&to->oi, &from->oi));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->oi);
  IGRAPH_CHECK(igraph_vector_copy(&to->ii, &from->ii));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->ii);
  IGRAPH_CHECK(igraph_vector_copy(&to->os, &from->os));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->os);
  IGRAPH_CHECK(igraph_vector_copy(&to->is, &from->is));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->is);

  IGRAPH_I_ATTRIBUTE_COPY(to, from, 1,1,1); /* does IGRAPH_CHECK */

  IGRAPH_FINALLY_CLEAN(6);
  return 0;
}
コード例 #3
0
/**
 * \ingroup interface
 * \function igraph_delete_vertices
 * \brief Removes vertices (with all their edges) from the graph.
 *
 * </para><para>
 * This function changes the ids of the vertices (except in some very
 * special cases, but these should not be relied on anyway).
 *
 * </para><para>
 * This function invalidates all iterators.
 * 
 * \param graph The graph to work on.
 * \param vertices The ids of the vertices to remove in a 
 *                 vector. The vector may contain the same id more
 *                 than once.
 * \return Error code:
 *         \c IGRAPH_EINVVID: invalid vertex id.
 *
 * Time complexity: O(|V|+|E|),
 * |V| and 
 * |E| are the number of vertices and
 * edges in the original graph.
 */
int igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertices) {

  long int no_of_edges=igraph_ecount(graph);
  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_t edge_recoding, vertex_recoding;
  igraph_vit_t vit;
  igraph_t newgraph;
  long int i, j;
  long int remaining_vertices, remaining_edges;
  
  IGRAPH_VECTOR_INIT_FINALLY(&vertex_recoding, no_of_nodes);
  IGRAPH_VECTOR_INIT_FINALLY(&edge_recoding, no_of_edges);
 
  IGRAPH_CHECK(igraph_vit_create(graph, vertices, &vit));
  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
  
  /* mark the vertices to delete */
  for (; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit) ) {
    long int vertex=IGRAPH_VIT_GET(vit);
    if (vertex < 0 || vertex >= no_of_nodes) {
      IGRAPH_ERROR("Cannot delete vertices", IGRAPH_EINVVID);
    }
    VECTOR(vertex_recoding)[vertex]=1;
  }
  /* create vertex recoding vector */
  for (remaining_vertices=0, i=0; i<no_of_nodes; i++) {
    if (VECTOR(vertex_recoding)[i]==0) {
      VECTOR(vertex_recoding)[i]=remaining_vertices+1;
      remaining_vertices++;
    } else {
      VECTOR(vertex_recoding)[i]=0;
    }
  }
  /* create edge recoding vector */
  for (remaining_edges=0, i=0; i<no_of_edges; i++) {
    long int from=VECTOR(graph->from)[i];
    long int to=VECTOR(graph->to)[i];
    if (VECTOR(vertex_recoding)[from] != 0 &&
	VECTOR(vertex_recoding)[to  ] != 0) {
      VECTOR(edge_recoding)[i]=remaining_edges+1;
      remaining_edges++;
    } 
  }

  /* start creating the graph */
  newgraph.n=remaining_vertices;
  newgraph.directed=graph->directed;  

  /* allocate vectors */
  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.from, remaining_edges);
  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.to, remaining_edges);
  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.oi, remaining_edges);
  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.ii, remaining_edges);
  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.os, remaining_vertices+1);
  IGRAPH_VECTOR_INIT_FINALLY(&newgraph.is, remaining_vertices+1);
  
  /* Add the edges */
  for (i=0, j=0; j<remaining_edges; i++) {
    if (VECTOR(edge_recoding)[i]>0) {
      long int from=VECTOR(graph->from)[i];
      long int to=VECTOR(graph->to  )[i];
      VECTOR(newgraph.from)[j]=VECTOR(vertex_recoding)[from]-1;
      VECTOR(newgraph.to  )[j]=VECTOR(vertex_recoding)[to]-1;
      j++;
    }
  }
  /* update oi & ii */
  IGRAPH_CHECK(igraph_vector_order(&newgraph.from, &newgraph.to, &newgraph.oi, 
				   remaining_vertices));
  IGRAPH_CHECK(igraph_vector_order(&newgraph.to, &newgraph.from, &newgraph.ii, 
				   remaining_vertices));  

  IGRAPH_CHECK(igraph_i_create_start(&newgraph.os, &newgraph.from, 
				     &newgraph.oi, remaining_vertices));
  IGRAPH_CHECK(igraph_i_create_start(&newgraph.is, &newgraph.to,
				     &newgraph.ii, remaining_vertices));
  
  /* attributes */
  IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
  IGRAPH_FINALLY_CLEAN(6);
  IGRAPH_FINALLY(igraph_destroy, &newgraph);
  IGRAPH_I_ATTRIBUTE_DELETE_VERTICES(&newgraph, &edge_recoding, 
				     &vertex_recoding);
  
  igraph_vit_destroy(&vit);
  igraph_vector_destroy(&edge_recoding);
  igraph_vector_destroy(&vertex_recoding);
  igraph_destroy(graph);
  *graph=newgraph;

  IGRAPH_FINALLY_CLEAN(4);
  return 0;
}
コード例 #4
0
ファイル: operators.c プロジェクト: GennadyKharlam/igraph
int igraph_difference(igraph_t *res, 
		      const igraph_t *orig, const igraph_t *sub) {

  /* Quite nasty, but we will use that an edge adjacency list
     contains the vertices according to the order of the 
     vertex ids at the "other" end of the edge. */

  long int no_of_nodes_orig=igraph_vcount(orig);
  long int no_of_nodes_sub =igraph_vcount(sub);
  long int no_of_nodes=no_of_nodes_orig;
  long int smaller_nodes;
  igraph_bool_t directed=igraph_is_directed(orig);
  igraph_vector_t edges;
  igraph_vector_t edge_ids;
  igraph_vector_t *nei1, *nei2;
  igraph_inclist_t inc_orig, inc_sub;
  long int i;
  igraph_integer_t v1, v2;

  if (directed != igraph_is_directed(sub)) {
    IGRAPH_ERROR("Cannot subtract directed and undirected graphs",
		 IGRAPH_EINVAL);
  }
  
  IGRAPH_VECTOR_INIT_FINALLY(&edge_ids, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_CHECK(igraph_inclist_init(orig, &inc_orig, IGRAPH_OUT));
  IGRAPH_FINALLY(igraph_inclist_destroy, &inc_orig);
  IGRAPH_CHECK(igraph_inclist_init(sub, &inc_sub, IGRAPH_OUT));
  IGRAPH_FINALLY(igraph_inclist_destroy, &inc_sub);
  
  smaller_nodes=no_of_nodes_orig > no_of_nodes_sub ?
    no_of_nodes_sub : no_of_nodes_orig;
  
  for (i=0; i<smaller_nodes; i++) {
    long int n1, n2, e1, e2;
    IGRAPH_ALLOW_INTERRUPTION();
    nei1=igraph_inclist_get(&inc_orig, i);
    nei2=igraph_inclist_get(&inc_sub, i);
    n1=igraph_vector_size(nei1)-1;
    n2=igraph_vector_size(nei2)-1;
    while (n1>=0 && n2>=0) {
      e1=(long int) VECTOR(*nei1)[n1];
      e2=(long int) VECTOR(*nei2)[n2];
      v1=IGRAPH_OTHER(orig, e1, i);
      v2=IGRAPH_OTHER(sub, e2, i);
      
      if (!directed && v1<i) { 
	n1--;
      } else if (!directed && v2<i) {
	n2--;
      } else if (v1>v2) {
	IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
	n1--;	
      } else if (v2>v1) {
	n2--;
      } else {
	n1--;
	n2--;
      }
    }
    
    /* Copy remaining edges */
    while (n1>=0) {
      e1=(long int) VECTOR(*nei1)[n1];
      v1=IGRAPH_OTHER(orig, e1, i);
      if (directed || v1 >= i) { 
	IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
      }
      n1--;
    }
  }

  /* copy remaining edges, use the previous value of 'i' */
  for (; i<no_of_nodes_orig; i++) {
    long int n1, e1;
    nei1=igraph_inclist_get(&inc_orig, i);
    n1=igraph_vector_size(nei1)-1;
    while (n1>=0) {
      e1=(long int) VECTOR(*nei1)[n1];
      v1=IGRAPH_OTHER(orig, e1, i);
      if (directed || v1 >= i) { 
	IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
      }
      n1--;
    }
  }

  igraph_inclist_destroy(&inc_sub);
  igraph_inclist_destroy(&inc_orig);
  IGRAPH_FINALLY_CLEAN(2);
  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes,
			     directed));
  igraph_vector_destroy(&edges);  
  IGRAPH_FINALLY_CLEAN(1);

  /* Attributes */
  if (orig->attr) {
    IGRAPH_I_ATTRIBUTE_DESTROY(res);
    IGRAPH_I_ATTRIBUTE_COPY(res, orig, /*graph=*/1, /*vertex=*/1, /*edge=*/0);
    IGRAPH_CHECK(igraph_i_attribute_permute_edges(orig, res, &edge_ids));
  }
  
  igraph_vector_destroy(&edge_ids);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}
コード例 #5
0
ファイル: bipartite.c プロジェクト: FEYoung/rigraph
int igraph_i_bipartite_projection(const igraph_t *graph,
				  const igraph_vector_bool_t *types,
				  igraph_t *proj,
				  int which,
				  igraph_vector_t *multiplicity) {
  
  long int no_of_nodes=igraph_vcount(graph);
  long int i, j, k;
  igraph_integer_t remaining_nodes=0;
  igraph_vector_t vertex_perm, vertex_index;
  igraph_vector_t edges;
  igraph_adjlist_t adjlist;
  igraph_vector_int_t *neis1, *neis2;
  long int neilen1, neilen2;
  igraph_vector_long_t added;
  igraph_vector_t mult;

  if (which < 0) { return 0; }
  
  IGRAPH_VECTOR_INIT_FINALLY(&vertex_perm, 0);
  IGRAPH_CHECK(igraph_vector_reserve(&vertex_perm, no_of_nodes));
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&vertex_index, no_of_nodes);
  IGRAPH_CHECK(igraph_vector_long_init(&added, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &added);
  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
  if (multiplicity) { 
    IGRAPH_VECTOR_INIT_FINALLY(&mult, no_of_nodes); 
    igraph_vector_clear(multiplicity);
  }
  
  for (i=0; i<no_of_nodes; i++) {
    if (VECTOR(*types)[i] == which) {
      VECTOR(vertex_index)[i] = ++remaining_nodes;
      igraph_vector_push_back(&vertex_perm, i);
    }
  }

  for (i=0; i<no_of_nodes; i++) {
    if (VECTOR(*types)[i] == which) {
      long int new_i=(long int) VECTOR(vertex_index)[i]-1;
      long int iedges=0;
      neis1=igraph_adjlist_get(&adjlist, i);
      neilen1=igraph_vector_int_size(neis1);
      for (j=0; j<neilen1; j++) {
	long int nei=(long int) VECTOR(*neis1)[j];
	if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) {
	  IGRAPH_ERROR("Non-bipartite edge found in bipartite projection",
		       IGRAPH_EINVAL);
	}
	neis2=igraph_adjlist_get(&adjlist, nei);
	neilen2=igraph_vector_int_size(neis2);
	for (k=0; k<neilen2; k++) {
	  long int nei2=(long int) VECTOR(*neis2)[k], new_nei2;
	  if (nei2 <= i) { continue; }
	  if (VECTOR(added)[nei2] == i+1) { 
	    if (multiplicity) { VECTOR(mult)[nei2]+=1; }
	    continue; 
	  }
	  VECTOR(added)[nei2] = i+1;
	  if (multiplicity) { VECTOR(mult)[nei2]=1; }
	  iedges++;

	  IGRAPH_CHECK(igraph_vector_push_back(&edges, new_i));
	  if (multiplicity) { 
	    /* If we need the multiplicity as well, then we put in the
	       old vertex ids here and rewrite it later */
	    IGRAPH_CHECK(igraph_vector_push_back(&edges, nei2));
	  } else { 
	    new_nei2=(long int) VECTOR(vertex_index)[nei2]-1;
	    IGRAPH_CHECK(igraph_vector_push_back(&edges, new_nei2));
	  }
	}
      }
      if (multiplicity) {
	/* OK, we need to go through all the edges added for vertex new_i 
	   and check their multiplicity */
	long int now=igraph_vector_size(&edges);
	long int from=now-iedges*2;
	for (j=from; j<now; j+=2) {
	  long int nei2=(long int) VECTOR(edges)[j+1];
	  long int new_nei2=(long int) VECTOR(vertex_index)[nei2]-1;
	  long int m=(long int) VECTOR(mult)[nei2];
	  VECTOR(edges)[j+1]=new_nei2;
	  IGRAPH_CHECK(igraph_vector_push_back(multiplicity, m));
	}
      }
    } /* if VECTOR(*type)[i] == which */
  }

  if (multiplicity) { 
    igraph_vector_destroy(&mult);
    IGRAPH_FINALLY_CLEAN(1);
  }
  igraph_adjlist_destroy(&adjlist);
  igraph_vector_long_destroy(&added);
  igraph_vector_destroy(&vertex_index);
  IGRAPH_FINALLY_CLEAN(3);
  
  IGRAPH_CHECK(igraph_create(proj, &edges, remaining_nodes, 
			     /*directed=*/ 0));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  IGRAPH_FINALLY(igraph_destroy, proj);
  
  IGRAPH_I_ATTRIBUTE_DESTROY(proj);
  IGRAPH_I_ATTRIBUTE_COPY(proj, graph, 1, 0, 0);
  IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, proj, &vertex_perm));
  igraph_vector_destroy(&vertex_perm);
  IGRAPH_FINALLY_CLEAN(2);
  
  return 0;
}
コード例 #6
0
int igraph_to_undirected(igraph_t *graph,
			 igraph_to_undirected_t mode) {
  long int no_of_nodes=igraph_vcount(graph);
  long int no_of_edges=igraph_ecount(graph);
  igraph_vector_t edges;
  igraph_t newgraph;
  
  if (mode != IGRAPH_TO_UNDIRECTED_EACH &&
      mode != IGRAPH_TO_UNDIRECTED_COLLAPSE) {
    IGRAPH_ERROR("Cannot undirect graph, invalid mode", IGRAPH_EINVAL);
  }
  
  if (!igraph_is_directed(graph)) {
    return 0;
  }

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  
  if (mode==IGRAPH_TO_UNDIRECTED_EACH) {
    igraph_es_t es;
    igraph_eit_t eit;

    IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
    IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID));
    IGRAPH_FINALLY(igraph_es_destroy, &es);
    IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
    IGRAPH_FINALLY(igraph_eit_destroy, &eit);
    
    while (!IGRAPH_EIT_END(eit)) {
      long int edge=IGRAPH_EIT_GET(eit);
      igraph_integer_t from, to;
      igraph_edge(graph, edge, &from, &to);
      IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
      IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
      IGRAPH_EIT_NEXT(eit);
    }
    
    igraph_eit_destroy(&eit);
    igraph_es_destroy(&es);
    IGRAPH_FINALLY_CLEAN(2);
    
    IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_UNDIRECTED));
    IGRAPH_FINALLY(igraph_destroy, &newgraph);
    igraph_vector_destroy(&edges);
    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
    IGRAPH_FINALLY_CLEAN(2);
    igraph_destroy(graph);
    *graph=newgraph;
    
  } else if (mode==IGRAPH_TO_UNDIRECTED_COLLAPSE) {
    igraph_vector_t seen, nei;
    long int i,j;
    IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
    IGRAPH_VECTOR_INIT_FINALLY(&seen, no_of_nodes);
    IGRAPH_VECTOR_INIT_FINALLY(&nei, 0);
    
    for (i=0; i<no_of_nodes; i++) {
      IGRAPH_CHECK(igraph_neighbors(graph, &nei, i, IGRAPH_ALL));
      for (j=0; j<igraph_vector_size(&nei); j++) {
	long int node=VECTOR(nei)[j];
	if (VECTOR(seen)[node] != i+1 && node >= i) {
	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	  IGRAPH_CHECK(igraph_vector_push_back(&edges, node));
	  VECTOR(seen)[node]=i+1;
	}
      }
    }

    igraph_vector_destroy(&nei);
    igraph_vector_destroy(&seen);
    IGRAPH_FINALLY_CLEAN(2);

    IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_UNDIRECTED));
    IGRAPH_FINALLY(igraph_destroy, &newgraph);
    igraph_vector_destroy(&edges);
    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,0); /* no edge attributes */
    IGRAPH_FINALLY_CLEAN(2);
    igraph_destroy(graph);
    *graph=newgraph;
  }

  return 0;
}
コード例 #7
0
int igraph_to_directed(igraph_t *graph,
		       igraph_to_directed_t mode) {

  if (mode != IGRAPH_TO_DIRECTED_ARBITRARY &&
      mode != IGRAPH_TO_DIRECTED_MUTUAL) {
    IGRAPH_ERROR("Cannot directed graph, invalid mode", IGRAPH_EINVAL);
  }

  if (igraph_is_directed(graph)) {
    return 0;
  }

  if (mode==IGRAPH_TO_DIRECTED_ARBITRARY) {

    igraph_t newgraph;
    igraph_vector_t edges;
    long int no_of_edges=igraph_ecount(graph);
    long int no_of_nodes=igraph_vcount(graph);
    long int size=no_of_edges*2;
    IGRAPH_VECTOR_INIT_FINALLY(&edges, size);
    IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));

    IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes,
			       IGRAPH_DIRECTED));
    IGRAPH_FINALLY(igraph_destroy, &newgraph);
    igraph_vector_destroy(&edges);
    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
    IGRAPH_FINALLY_CLEAN(2);
    igraph_destroy(graph);
    *graph=newgraph;

  } else if (mode==IGRAPH_TO_DIRECTED_MUTUAL) {
    
    igraph_t newgraph;
    igraph_vector_t edges;
    igraph_vector_t index;
    long int no_of_edges=igraph_ecount(graph);
    long int no_of_nodes=igraph_vcount(graph);
    long int size=no_of_edges*4;
    long int i;
    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
    IGRAPH_CHECK(igraph_vector_reserve(&edges, size));
    IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
    IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*4));
    IGRAPH_VECTOR_INIT_FINALLY(&index, no_of_edges*2);
    for (i=0; i<no_of_edges; i++) {
      VECTOR(edges)[no_of_edges*2+i*2]  =VECTOR(edges)[i*2+1];
      VECTOR(edges)[no_of_edges*2+i*2+1]=VECTOR(edges)[i*2];
      VECTOR(index)[i] = VECTOR(index)[no_of_edges+i] = i+1;
    }

    IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes,
			       IGRAPH_DIRECTED));
    IGRAPH_FINALLY(igraph_destroy, &newgraph);
    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
    IGRAPH_CHECK(igraph_i_attribute_permute_edges(&newgraph, &index));
    
    igraph_vector_destroy(&index);
    igraph_vector_destroy(&edges);
    igraph_destroy(graph);
    IGRAPH_FINALLY_CLEAN(3);
    *graph=newgraph;
  }
  
  return 0;
}