igraph/ext/cIGraph_add_delete.c

316 lines
7.7 KiB
C

#include "igraph.h"
#include "ruby.h"
#include "cIGraph.h"
/* call-seq:
* graph.add_edges(edges) -> Fixnum
*
* Adds the edges in the edges Array to the graph. Edges are specified as an
* Array in the same way as with IGraph#new.
*
* Returns 0 on success.
*
* Example:
*
* g = IGraph.new([1,2,3,4],true)
* g.add_edges([1,4,2,3])
*
* Adds an extra directed edge to this trivial graph. Note that vertices
* must have already been added to the graph before they can be used in
* an edge (throws a IGraphError otherwise).
*/
VALUE cIGraph_add_edges(int argc, VALUE *argv, VALUE self){
igraph_t *graph;
igraph_vector_t edge_v;
VALUE vertex;
VALUE edges;
VALUE attrs;
VALUE v_ary;
int vid;
int code = 0;
int i;
igraph_vector_ptr_t edge_attr;
igraph_i_attribute_record_t e_attr_rec;
e_attr_rec.name = "__RUBY__";
e_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT;
e_attr_rec.value = (void*)rb_ary_new();
rb_scan_args(argc, argv, "11", &edges, &attrs);
//Initialize edge vector
IGRAPH_FINALLY(igraph_vector_destroy,&edge_v);
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&edge_attr);
IGRAPH_CHECK(igraph_vector_init_int(&edge_v,0));
IGRAPH_CHECK(igraph_vector_ptr_init(&edge_attr,0));
Data_Get_Struct(self, igraph_t, graph);
v_ary = ((VALUE*)graph->attr)[0];
//Loop through objects in edge Array
for (i=0; i<RARRAY_LEN(edges); i++) {
vertex = RARRAY_PTR(edges)[i];
if(rb_ary_includes(v_ary,vertex)){
vid = cIGraph_get_vertex_id(self, vertex);
} else {
rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices first");
}
IGRAPH_CHECK(igraph_vector_push_back(&edge_v,vid));
if (i % 2){
if (attrs != Qnil){
rb_ary_push((VALUE)e_attr_rec.value,RARRAY_PTR(attrs)[i/2]);
} else {
rb_ary_push((VALUE)e_attr_rec.value,Qnil);
}
}
}
IGRAPH_CHECK(igraph_vector_ptr_push_back(&edge_attr, &e_attr_rec));
if(igraph_vector_size(&edge_v) > 0){
IGRAPH_CHECK(code = igraph_add_edges(graph,&edge_v,&edge_attr));
}
igraph_vector_destroy(&edge_v);
igraph_vector_ptr_destroy(&edge_attr);
IGRAPH_FINALLY_CLEAN(2);
return INT2NUM(code);
}
/* call-seq:
* graph.add_vertices(vs) -> Fixnum
*
* Adds the vertices in the vs Array to the graph.
*
* Returns 0 on success.
*
* Example:
*
* g = IGraph.new([1,2,3,4],true)
* g.add_vertices([5,6,7,8])
*
* Adds 4 extra vertices to this graph. IGraph will silently ignore attempts
* to add a vertex twice to the same graph.
*/
VALUE cIGraph_add_vertices(VALUE self, VALUE vs){
igraph_t *graph;
VALUE vertex;
VALUE v_ary;
int code = 0;
int to_add;
int i;
igraph_vector_ptr_t vertex_attr;
igraph_i_attribute_record_t v_attr_rec;
v_attr_rec.name = "__RUBY__";
v_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT;
v_attr_rec.value = (void*)rb_ary_new();
IGRAPH_CHECK(igraph_vector_ptr_init(&vertex_attr,0));
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&vertex_attr);
Data_Get_Struct(self, igraph_t, graph);
v_ary = ((VALUE*)graph->attr)[0];
to_add = RARRAY_LEN(vs);
//Loop through objects in vertex array
for (i=0; i<RARRAY_LEN(vs); i++) {
vertex = RARRAY_PTR(vs)[i];
if(rb_ary_includes(v_ary,vertex)){
//Silently ignore duplicated additions
//rb_raise(cIGraphError, "Vertex already added to graph");
to_add--;
} else {
rb_ary_push((VALUE)v_attr_rec.value,RARRAY_PTR(vs)[i]);
}
}
IGRAPH_CHECK(igraph_vector_ptr_push_back(&vertex_attr,&v_attr_rec));
IGRAPH_CHECK(code = igraph_add_vertices(graph,to_add,&vertex_attr));
igraph_vector_ptr_destroy(&vertex_attr);
IGRAPH_FINALLY_CLEAN(1);
return INT2NUM(code);
}
/* call-seq:
* graph.add_edge(from,to) -> Fixnum
*
* Adds an edge between the two vertices given. This is just a convinience
* method, it is possible to use IGraph#add_edges to add a single edge as well
*
* Returns 0 on success.
*
* Example:
*
* g = IGraph.new([1,2,3,4],true)
* g.add_edge(1,4)
*
* Note that vertices must have already been added to the graph before
* they can be used in an edge (throws a IGraphError otherwise).
*/
VALUE cIGraph_add_edge(int argc, VALUE *argv, VALUE self){
igraph_t *graph;
igraph_vector_t edge_v;
igraph_vector_ptr_t edge_attr;
int code = 0;
VALUE v_ary;
VALUE from;
VALUE to;
VALUE attr;
igraph_i_attribute_record_t e_attr_rec;
e_attr_rec.name = "__RUBY__";
e_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT;
e_attr_rec.value = (void*)rb_ary_new();
rb_scan_args(argc, argv, "21", &from, &to, &attr);
//Initialize edge vector
IGRAPH_FINALLY(igraph_vector_destroy,&edge_v);
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&edge_attr);
IGRAPH_CHECK(igraph_vector_init_int(&edge_v,0));
IGRAPH_CHECK(igraph_vector_ptr_init(&edge_attr,0));
Data_Get_Struct(self, igraph_t, graph);
v_ary = ((VALUE*)graph->attr)[0];
if(rb_ary_includes(v_ary,from) && rb_ary_includes(v_ary,to)){
//If graph includes this vertex then look up the vertex number
IGRAPH_CHECK(igraph_vector_push_back(&edge_v,cIGraph_get_vertex_id(self, from)));
IGRAPH_CHECK(igraph_vector_push_back(&edge_v,cIGraph_get_vertex_id(self, to)));
rb_ary_push((VALUE)e_attr_rec.value,attr);
} else {
rb_raise(cIGraphError, "Unknown vertex in edge array. Use add_vertices");
}
IGRAPH_CHECK(igraph_vector_ptr_push_back(&edge_attr,&e_attr_rec));
IGRAPH_CHECK(code = igraph_add_edges(graph,&edge_v,&edge_attr));
igraph_vector_ptr_destroy(&edge_attr);
igraph_vector_destroy(&edge_v);
IGRAPH_FINALLY_CLEAN(2);
return INT2NUM(code);
}
/* call-seq:
* graph.add_vertex(v) -> Fixnum
*
* Adds the vertex to the graph. This is just a convinience method it is
* also possible to use IGraph#add_vertices to add a single vertex.
*
* Returns 0 on success.
*
* Example:
*
* g = IGraph.new([1,2,3,4],true)
* g.add_vertex(5)
*
* Adds 1 extra vertex to this graph. IGraph will silently ignore attempts
* to add a vertex twice to the same graph.
*/
VALUE cIGraph_add_vertex(VALUE self, VALUE v){
igraph_t *graph;
igraph_vector_ptr_t vertex_attr;
int code = 0;
VALUE v_ary;
igraph_i_attribute_record_t v_attr_rec;
v_attr_rec.name = "__RUBY__";
v_attr_rec.type = IGRAPH_ATTRIBUTE_PY_OBJECT;
v_attr_rec.value = (void*)rb_ary_new();
IGRAPH_CHECK(igraph_vector_ptr_init(&vertex_attr,0));
IGRAPH_FINALLY(igraph_vector_ptr_destroy,&vertex_attr);
Data_Get_Struct(self, igraph_t, graph);
v_ary = ((VALUE*)graph->attr)[0];
//Loop through objects in vertex array
if(rb_ary_includes(v_ary,v)){
//rb_raise(cIGraphError, "Vertex already added to graph");
igraph_vector_ptr_destroy(&vertex_attr);
IGRAPH_FINALLY_CLEAN(1);
return code;
} else {
rb_ary_push((VALUE)v_attr_rec.value,v);
}
IGRAPH_CHECK(igraph_vector_ptr_push_back(&vertex_attr,&v_attr_rec));
IGRAPH_CHECK(code = igraph_add_vertices(graph,1,&vertex_attr));
igraph_vector_ptr_destroy(&vertex_attr);
IGRAPH_FINALLY_CLEAN(1);
return INT2NUM(code);
}
/* call-seq:
* graph.delete_edge(from,to)
*
* Deletes the edge connecting the two vertices given.
*/
VALUE cIGraph_delete_edge(VALUE self, VALUE from, VALUE to){
igraph_t *graph;
igraph_integer_t eid = 0;
int from_i;
int to_i;
Data_Get_Struct(self, igraph_t, graph);
from_i = cIGraph_get_vertex_id(self,from);
to_i = cIGraph_get_vertex_id(self,to);
igraph_get_eid(graph,&eid,from_i,to_i,1);
igraph_delete_edges(graph,igraph_ess_1(eid));
return Qnil;
}
/* call-seq:
* graph.delete_vertex(v)
*
* Delete the vertex specified.
*/
VALUE cIGraph_delete_vertex(VALUE self, VALUE v){
igraph_t *graph;
igraph_vs_t vs;
Data_Get_Struct(self, igraph_t, graph);
igraph_vs_1(&vs, cIGraph_get_vertex_id(self,v));
igraph_delete_vertices(graph,vs);
igraph_vs_destroy(&vs);
return Qnil;
}