haskell-igraph 0.3.0 → 0.4.0
raw patch · 40 files changed
+3604/−565 lines, 40 filesdep +cerealdep +cereal-conduitdep +conduitdep −binary
Dependencies added: cereal, cereal-conduit, conduit
Dependencies removed: binary
Files
- ChangeLog.md +7/−0
- README.md +0/−0
- cbits/bytestring.c +359/−0
- cbits/haskell_attributes.c +1900/−0
- cbits/haskell_igraph.c +28/−0
- cbits/haskelligraph.c +0/−36
- cbits/haskelligraph.h +0/−17
- haskell-igraph.cabal +41/−26
- include/bytestring.h +111/−0
- include/haskell_attributes.h +218/−0
- include/haskell_igraph.h +8/−0
- src/IGraph.hs +169/−84
- src/IGraph/Clique.hs +2/−2
- src/IGraph/Community.hs +25/−27
- src/IGraph/Exporter/GEXF.hs +33/−17
- src/IGraph/Exporter/Graphics.hs +1/−1
- src/IGraph/Generators.hs +33/−5
- src/IGraph/Internal/Arpack.chs +4/−3
- src/IGraph/Internal/Attribute.chs +44/−21
- src/IGraph/Internal/C2HS.hs +73/−0
- src/IGraph/Internal/Clique.chs +3/−3
- src/IGraph/Internal/Community.chs +14/−14
- src/IGraph/Internal/Constants.chs +6/−0
- src/IGraph/Internal/Data.chs +168/−65
- src/IGraph/Internal/Graph.chs +51/−25
- src/IGraph/Internal/Initialization.chs +1/−1
- src/IGraph/Internal/Isomorphism.chs +6/−6
- src/IGraph/Internal/Layout.chs +8/−8
- src/IGraph/Internal/Motif.chs +5/−5
- src/IGraph/Internal/Selector.chs +22/−34
- src/IGraph/Internal/Structure.chs +25/−25
- src/IGraph/Isomorphism.hs +1/−1
- src/IGraph/Layout.hs +5/−5
- src/IGraph/Motif.hs +1/−1
- src/IGraph/Mutable.hs +73/−71
- src/IGraph/Structure.hs +72/−57
- src/IGraph/Types.hs +16/−0
- tests/Test/Attributes.hs +60/−0
- tests/Test/Basic.hs +9/−5
- tests/test.hs +2/−0
+ ChangeLog.md view
@@ -0,0 +1,7 @@+Revision history for haskell-igraph+===================================++v0.4.0 -- 2018-04-20+-------------------++* A new attribute interface written in C. The graph attributes are now directly serialized into bytestring using "cereal" (before we used the `Show` instance).
+ README.md view
+ cbits/bytestring.c view
@@ -0,0 +1,359 @@+#include "bytestring.h"+#include <assert.h>+#include <string.h>++int bsvector_init(bsvector_t *sv, long int len) {+ long int i;+ sv->data=igraph_Calloc(len, bytestring_t*);+ if (sv->data==0) {+ IGRAPH_ERROR("bsvector init failed", IGRAPH_ENOMEM);+ }+ for (i=0; i<len; i++) {+ sv->data[i]=new_bytestring(0);+ if (sv->data[i]==0) {+ bsvector_destroy(sv);+ IGRAPH_ERROR("bsvector init failed", IGRAPH_ENOMEM);+ }+ }+ sv->len=len;++ return 0;+}++void bsvector_destroy(bsvector_t *sv) {+ long int i;+ assert(sv != 0);+ if (sv->data != 0) {+ for (i=0; i<sv->len; i++) {+ if (sv->data[i] != 0) {+ destroy_bytestring(sv->data[i]);+ }+ }+ igraph_Free(sv->data);+ }+}++void bsvector_get(const bsvector_t *sv, long int idx, bytestring_t **value) {+ assert(sv != 0);+ assert(sv->data != 0);+ assert(sv->data[idx] != 0);+ *value = sv->data[idx];+}++int bsvector_set(bsvector_t *sv, long int idx, const bytestring_t *value) {+ assert(sv != 0);+ assert(sv->data != 0);++ if (sv->data[idx] != 0) {+ destroy_bytestring(sv->data[idx]);+ }+ sv->data[idx] = new_bytestring(value->len);++ memcpy(sv->data[idx]->value, value->value, value->len * sizeof(char));++ return 0;+}++void bsvector_remove_section(bsvector_t *v, long int from, long int to) {+ long int i;++ assert(v != 0);+ assert(v->data != 0);++ for (i=from; i<to; i++) {+ if (v->data[i] != 0) {+ destroy_bytestring(v->data[i]);+ }+ }+ for (i=0; i<v->len-to; i++) {+ v->data[from+i]=v->data[to+i];+ }++ v->len -= (to-from);+}++void bsvector_remove(bsvector_t *v, long int elem) {+ assert(v != 0);+ assert(v->data != 0);+ bsvector_remove_section(v, elem, elem+1);+}++/*+void bsvector_move_interval(bsvector_t *v, long int begin,+ long int end, long int to) {+ long int i;+ assert(v != 0);+ assert(v->data != 0);+ for (i=to; i<to+end-begin; i++) {+ if (v->data[i] != 0) {+ destroy_bytestring(v->data[i]);+ }+ }+ for (i=0; i<end-begin; i++) {+ if (v->data[begin+i] != 0) {+ size_t len=strlen(v->data[begin+i])+1;+ v->data[to+i]=igraph_Calloc(len, char);+ memcpy(v->data[to+i], v->data[begin+i], sizeof(char)*len);+ }+ }+}+*/++int bsvector_copy(bsvector_t *to, const bsvector_t *from) {+ long int i;+ bytestring_t *str;+ assert(from != 0);+/* assert(from->data != 0); */+ to->data=igraph_Calloc(from->len, bytestring_t*);+ if (to->data==0) {+ IGRAPH_ERROR("Cannot copy string vector", IGRAPH_ENOMEM);+ }+ to->len=from->len;++ for (i=0; i<from->len; i++) {+ int ret;+ bsvector_get(from, i, &str);+ ret=bsvector_set(to, i, str);+ if (ret != 0) {+ bsvector_destroy(to);+ IGRAPH_ERROR("cannot copy string vector", ret);+ }+ }++ return 0;+}++int bsvector_append(bsvector_t *to, const bsvector_t *from) {+ long int len1=bsvector_size(to), len2=bsvector_size(from);+ long int i;+ igraph_bool_t error=0;+ IGRAPH_CHECK(bsvector_resize(to, len1+len2));+ for (i=0; i<len2; i++) {+ if (from->data[i]->len > 0) {+ bsvector_set(to, len1+i, from->data[i]);+ if (!to->data[len1+i]) {+ error=1;+ break;+ }+ }+ }+ if (error) {+ bsvector_resize(to, len1);+ IGRAPH_ERROR("Cannot append string vector", IGRAPH_ENOMEM);+ }+ return 0;+}++void bsvector_clear(bsvector_t *sv) {+ long int i, n=bsvector_size(sv);+ bytestring_t **tmp;++ for (i=0; i<n; i++) {+ destroy_bytestring(sv->data[i]);+ }+ sv->len=0;+ /* try to give back some memory */+ tmp=igraph_Realloc(sv->data, 1, bytestring_t*);+ if (tmp != 0) {+ sv->data=tmp;+ }+}++int bsvector_resize(bsvector_t* v, long int newsize) {+ long int toadd = newsize - v->len, i, j;+ bytestring_t **tmp;+ long int reallocsize=newsize;+ if (reallocsize==0) { reallocsize=1; }++ assert(v != 0);+ assert(v->data != 0);+ if (newsize < v->len) {+ for (i=newsize; i<v->len; i++) {+ destroy_bytestring(v->data[i]);+ }+ /* try to give back some space */+ tmp=igraph_Realloc(v->data, (size_t) reallocsize, bytestring_t*);+ if (tmp != 0) {+ v->data=tmp;+ }+ } else if (newsize > v->len) {+ igraph_bool_t error=0;+ tmp=igraph_Realloc(v->data, (size_t) reallocsize, bytestring_t*);+ if (tmp==0) {+ IGRAPH_ERROR("cannot resize string vector", IGRAPH_ENOMEM);+ }+ v->data = tmp;++ for (i=0; i<toadd; i++) {+ v->data[v->len+i] = new_bytestring(0);+ if (v->data[v->len+i] == 0) {+ error=1;+ break;+ }+ }+ if (error) {+ /* There was an error, free everything we've allocated so far */+ for (j=0; j<i; j++) {+ if (v->data[v->len+i] != 0) {+ destroy_bytestring(v->data[v->len+i]);+ }+ }+ /* Try to give back space */+ tmp=igraph_Realloc(v->data, (size_t) (v->len), bytestring_t*);+ if (tmp != 0) {+ v->data=tmp;+ }+ IGRAPH_ERROR("Cannot resize string vector", IGRAPH_ENOMEM);+ }+ }+ v->len = newsize;++ return 0;+}++int bsvector_add(bsvector_t *v, const bytestring_t *value) {+ long int s=bsvector_size(v);+ bytestring_t **tmp;+ assert(v != 0);+ assert(v->data != 0);+ tmp=igraph_Realloc(v->data, (size_t) s+1, bytestring_t*);+ if (tmp == 0) {+ IGRAPH_ERROR("cannot add string to string vector", IGRAPH_ENOMEM);+ }+ v->data=tmp;+ v->data[s]=new_bytestring(value->len);+ if (v->data[s]==0) {+ IGRAPH_ERROR("cannot add string to string vector", IGRAPH_ENOMEM);+ }+ bsvector_set(v, s, value);+ v->len += 1;++ return 0;+}++/**+ * \ingroup strvector+ * \function igraph_strvector_permdelete+ * \brief Removes elements from a string vector (for internal use)+ */++void bsvector_permdelete(bsvector_t *v, const igraph_vector_t *index,+ long int nremove) {+ long int i;+ bytestring_t **tmp;+ assert(v != 0);+ assert(v->data != 0);++ for (i=0; i<bsvector_size(v); i++) {+ if (VECTOR(*index)[i] != 0) {+ v->data[ (long int) VECTOR(*index)[i]-1 ] = v->data[i];+ } else {+ destroy_bytestring(v->data[i]);+ }+ }+ /* Try to make it shorter */+ tmp=igraph_Realloc(v->data, v->len-nremove ?+ (size_t) (v->len-nremove) : 1, bytestring_t*);+ if (tmp != 0) {+ v->data=tmp;+ }+ v->len -= nremove;+}++/**+ * \ingroup strvector+ * \function igraph_strvector_remove_negidx+ * \brief Removes elements from a string vector (for internal use)+ */++void bsvector_remove_negidx(bsvector_t *v, const igraph_vector_t *neg,+ long int nremove) {+ long int i, idx=0;+ bytestring_t **tmp;+ assert(v != 0);+ assert(v->data != 0);+ for (i=0; i<bsvector_size(v); i++) {+ if (VECTOR(*neg)[i] >= 0) {+ v->data[idx++] = v->data[i];+ } else {+ destroy_bytestring(v->data[i]);+ }+ }+ /* Try to give back some memory */+ tmp=igraph_Realloc(v->data, v->len-nremove ?+ (size_t) (v->len-nremove) : 1, bytestring_t*);+ if (tmp != 0) {+ v->data=tmp;+ }+ v->len -= nremove;+}++int bsvector_index(const bsvector_t *v, bsvector_t *newv,+ const igraph_vector_t *idx) {+ long int i, newlen=igraph_vector_size(idx);+ IGRAPH_CHECK(bsvector_resize(newv, newlen));++ for (i=0; i<newlen; i++) {+ long int j=(long int) VECTOR(*idx)[i];+ bytestring_t *str;+ bsvector_get(v, j, &str);+ bsvector_set(newv, i, str);+ }++ return 0;+}++long int bsvector_size(const bsvector_t *sv) {+ assert(sv != 0);+ return sv->len;+}++bytestring_t* new_bytestring(int n) {+ bytestring_t *newstr = igraph_Calloc(1, bytestring_t);+ char *str = igraph_Calloc(n, char);+ newstr->len = n;+ newstr->value = str;+ return newstr;+}++void destroy_bytestring(bytestring_t* str) {+ if (str != NULL) {+ free(str->value);+ free(str);+ }+}++char* bytestring_to_char(bytestring_t* from) {+ char *str = igraph_Calloc(from->len + sizeof(long int), char);+ memcpy(str, &from->len, sizeof(long int));+ memcpy(str + sizeof(long int), from->value, from->len);+ return str;+}++bytestring_t* char_to_bytestring(char* from) {+ unsigned long int *n;+ memcpy(n, from, sizeof(long int));+ bytestring_t *str = new_bytestring(*n);+ memcpy(str->value, from+sizeof(long int), *n);+ return str;+}++igraph_strvector_t* bsvector_to_strvector(bsvector_t* from) {+ igraph_strvector_t *str;+ size_t i;+ igraph_strvector_init(str, from->len);+ for (i = 0; i++; i < from->len) {+ igraph_strvector_set(str, i, bytestring_to_char(from->data[i]));+ }+ return str;+}++bsvector_t* strvector_to_bsvector(igraph_strvector_t* from) {+ bsvector_t *str;+ size_t i;+ bsvector_init(str, from->len);+ for (i = 0; i++; i < from->len) {+ bsvector_set(str, i, char_to_bytestring(from->data[i]));+ }+ return str;+}
+ cbits/haskell_attributes.c view
@@ -0,0 +1,1900 @@+#include "haskell_attributes.h"++/* An attribute is either a numeric vector (vector_t) or a string+ vector (strvector_t). The attribute itself is stored in a+ struct igraph_attribute_record_t, there is one such object for each+ attribute. The igraph_t has a pointer to an array of three+ vector_ptr_t's which contains pointers to+ igraph_haskell_attribute_t's. Graph attributes are first, then vertex+ and edge attributes. */++igraph_bool_t igraph_haskell_attribute_find(const igraph_vector_ptr_t *ptrvec,+ const char *name, long int *idx) {+ long int i, n=igraph_vector_ptr_size(ptrvec);+ igraph_bool_t l=0;+ for (i=0; !l && i<n; i++) {+ igraph_attribute_record_t *rec=VECTOR(*ptrvec)[i];+ l= !strcmp(rec->name, name);+ }+ if (idx) { *idx=i-1; }+ return l;+}++int igraph_haskell_attributes_copy_attribute_record(igraph_attribute_record_t **newrec,+ const igraph_attribute_record_t *rec) {+ bsvector_t *str, *newstr;++ *newrec=igraph_Calloc(1, igraph_attribute_record_t);+ if (!(*newrec)) { IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); }+ IGRAPH_FINALLY(igraph_free, *newrec);+ (*newrec)->type=rec->type;+ (*newrec)->name=strdup(rec->name);+ if (!(*newrec)->name) { IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); }+ IGRAPH_FINALLY(igraph_free, (void*)(*newrec)->name);++ if (rec->type == IGRAPH_ATTRIBUTE_STRING) {+ str=(bsvector_t*)rec->value;+ newstr=igraph_Calloc(1, bsvector_t);+ if (!newstr) {+ IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, newstr);+ IGRAPH_CHECK(bsvector_copy(newstr, str));+ IGRAPH_FINALLY(bsvector_destroy, newstr);+ (*newrec)->value=newstr;+ } else {+ IGRAPH_ERROR("Wrong attribute type", IGRAPH_ENOMEM);+ }++ IGRAPH_FINALLY_CLEAN(4);+ return 0;+}+++int igraph_haskell_attribute_init(igraph_t *graph, igraph_vector_ptr_t *attr) {+ igraph_attribute_record_t *attr_rec;+ long int i, n;+ igraph_haskell_attributes_t *nattr;++ n = attr ? igraph_vector_ptr_size(attr) : 0;++ nattr=igraph_Calloc(1, igraph_haskell_attributes_t);+ if (!nattr) {+ IGRAPH_ERROR("Can't init attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, nattr);++ IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->gal, n));+ IGRAPH_FINALLY(igraph_vector_ptr_destroy, &nattr->gal);+ IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->val, 0));+ IGRAPH_FINALLY(igraph_vector_ptr_destroy, &nattr->val);+ IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->eal, 0));+ IGRAPH_FINALLY_CLEAN(3);++ for (i=0; i<n; i++) {+ IGRAPH_CHECK(igraph_haskell_attributes_copy_attribute_record(+ &attr_rec, VECTOR(*attr)[i]));+ VECTOR(nattr->gal)[i] = attr_rec;+ }++ graph->attr=nattr;++ return 0;+}++void igraph_haskell_attribute_destroy(igraph_t *graph) {+ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *als[3]= { &attr->gal, &attr->val, &attr->eal };+ long int i, n, a;+ bsvector_t *str;+ igraph_attribute_record_t *rec;+ for (a=0; a<3; a++) {+ n=igraph_vector_ptr_size(als[a]);+ for (i=0; i<n; i++) {+ rec=VECTOR(*als[a])[i];+ if (rec) {+ if (rec->type == IGRAPH_ATTRIBUTE_STRING) {+ str=(bsvector_t*)rec->value;+ bsvector_destroy(str);+ igraph_free(str);+ }+ igraph_free((char*)rec->name);+ igraph_free(rec);+ }+ }+ }+ igraph_vector_ptr_destroy(&attr->gal);+ igraph_vector_ptr_destroy(&attr->val);+ igraph_vector_ptr_destroy(&attr->eal);+ igraph_free(graph->attr);+ graph->attr=0;+}++/* Almost the same as destroy, but we might have null pointers */++void igraph_haskell_attribute_copy_free(igraph_haskell_attributes_t *attr) {+ igraph_vector_ptr_t *als[3] = { &attr->gal, &attr->val, &attr->eal };+ long int i, n, a;+ bsvector_t *str;+ igraph_attribute_record_t *rec;+ for (a=0; a<3; a++) {+ n=igraph_vector_ptr_size(als[a]);+ for (i=0; i<n; i++) {+ rec=VECTOR(*als[a])[i];+ if (!rec) { continue; }+ if (rec->type == IGRAPH_ATTRIBUTE_STRING) {+ str=(bsvector_t*)rec->value;+ bsvector_destroy(str);+ igraph_free(str);+ }+ igraph_free((char*)rec->name);+ igraph_free(rec);+ }+ }+}++/* No reference counting here. If you use attributes in C you should+ know what you're doing. */++int igraph_haskell_attribute_copy(igraph_t *to, const igraph_t *from,+ igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea) {+ igraph_haskell_attributes_t *attrfrom=from->attr, *attrto;+ igraph_vector_ptr_t *alto[3], *alfrom[3]={ &attrfrom->gal, &attrfrom->val,+ &attrfrom->eal };+ long int i, n, a;+ igraph_bool_t copy[3] = { ga, va, ea };+ to->attr=attrto=igraph_Calloc(1, igraph_haskell_attributes_t);+ if (!attrto) {+ IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, attrto);+ IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->gal, 0);+ IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->val, 0);+ IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->eal, 0);+ IGRAPH_FINALLY_CLEAN(3);+ IGRAPH_FINALLY(igraph_haskell_attribute_copy_free, attrto);++ alto[0]=&attrto->gal; alto[1]=&attrto->val; alto[2]=&attrto->eal;+ for (a=0; a<3; a++) {+ if (copy[a]) {+ n=igraph_vector_ptr_size(alfrom[a]);+ IGRAPH_CHECK(igraph_vector_ptr_resize(alto[a], n));+ igraph_vector_ptr_null(alto[a]);+ for (i=0; i<n; i++) {+ igraph_attribute_record_t *newrec;+ IGRAPH_CHECK(igraph_haskell_attributes_copy_attribute_record(&newrec,+ VECTOR(*alfrom[a])[i]));+ VECTOR(*alto[a])[i]=newrec;+ }+ }+ }++ IGRAPH_FINALLY_CLEAN(2);+ return 0;+}++int igraph_haskell_attribute_add_vertices(igraph_t *graph, long int nv,+ igraph_vector_ptr_t *nattr) {+ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *val=&attr->val;+ long int length=igraph_vector_ptr_size(val);+ long int nattrno=nattr==NULL ? 0 : igraph_vector_ptr_size(nattr);+ long int origlen=igraph_vcount(graph)-nv;+ long int newattrs=0, i;+ igraph_vector_t news;++ /* First add the new attributes if any */+ newattrs=0;+ IGRAPH_VECTOR_INIT_FINALLY(&news, 0);+ for (i=0; i<nattrno; i++) {+ igraph_attribute_record_t *nattr_entry=VECTOR(*nattr)[i];+ const char *nname=nattr_entry->name;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(val, nname, &j);+ if (!l) {+ newattrs++;+ IGRAPH_CHECK(igraph_vector_push_back(&news, i));+ } else {+ /* check types */+ if (nattr_entry->type != ((igraph_attribute_record_t*)VECTOR(*val)[j])->type) {+ IGRAPH_ERROR("You cannot mix attribute types", IGRAPH_EINVAL);+ }+ }+ }++ /* Add NA/empty string vectors for the existing vertices */+ if (newattrs != 0) {+ for (i=0; i<newattrs; i++) {+ igraph_attribute_record_t *tmp=VECTOR(*nattr)[(long int)VECTOR(news)[i]];+ igraph_attribute_record_t *newrec=igraph_Calloc(1, igraph_attribute_record_t);+ igraph_attribute_type_t type=tmp->type;+ if (!newrec) {+ IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, newrec);+ newrec->type=type;+ newrec->name=strdup(tmp->name);+ if (!newrec->name) {+ IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, (char*)newrec->name);+ if (type==IGRAPH_ATTRIBUTE_STRING) {+ bsvector_t *newstr=igraph_Calloc(1, bsvector_t);+ if (!newstr) {+ IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, newstr);+ BSVECTOR_INIT_FINALLY(newstr, origlen);+ newrec->value=newstr;+ }+ IGRAPH_CHECK(igraph_vector_ptr_push_back(val, newrec));+ IGRAPH_FINALLY_CLEAN(4);+ }+ length=igraph_vector_ptr_size(val);+ }+++ /* Now append the new values */+ for (i=0; i<length; i++) {+ igraph_attribute_record_t *oldrec=VECTOR(*val)[i];+ igraph_attribute_record_t *newrec=0;+ const char *name=oldrec->name;+ long int j;+ igraph_bool_t l=0;+ if (nattr) { l=igraph_haskell_attribute_find(nattr, name, &j); }+ if (l) {+ /* This attribute is present in nattr */+ bsvector_t *oldstr, *newstr;+ newrec=VECTOR(*nattr)[j];+ oldstr=(bsvector_t*)oldrec->value;+ newstr=(bsvector_t*)newrec->value;+ if (oldrec->type != newrec->type) {+ IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);+ }+ if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) {+ if (nv != bsvector_size(newstr)) {+ IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL);+ }+ IGRAPH_CHECK(bsvector_append(oldstr, newstr));+ } else {+ IGRAPH_WARNING("Invalid attribute type");+ }+ } else {+ /* No such attribute, append NA's */+ bsvector_t *oldstr=(bsvector_t*)oldrec->value;+ if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) {+ IGRAPH_CHECK(bsvector_resize(oldstr, origlen+nv));+ } else {+ IGRAPH_WARNING("Invalid attribute type");+ }+ }+ }++ igraph_vector_destroy(&news);+ IGRAPH_FINALLY_CLEAN(1);++ return 0;+}++void igraph_haskell_attribute_permute_free(igraph_vector_ptr_t *v) {+ long int i, n=igraph_vector_ptr_size(v);+ for (i=0; i<n; i++) {+ igraph_attribute_record_t *rec=VECTOR(*v)[i];+ igraph_Free(rec->name);+ if (rec->type == IGRAPH_ATTRIBUTE_STRING) {+ bsvector_t *strv= (bsvector_t*) rec->value;+ bsvector_destroy(strv);+ igraph_Free(strv);+ }+ igraph_Free(rec);+ }+ igraph_vector_ptr_clear(v);+}++int igraph_haskell_attribute_permute_vertices(const igraph_t *graph,+ igraph_t *newgraph,+ const igraph_vector_t *idx) {++ if (graph==newgraph) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *val=&attr->val;+ long int valno=igraph_vector_ptr_size(val);+ long int i;++ for (i=0; i<valno; i++) {+ igraph_attribute_record_t *oldrec=VECTOR(*val)[i];+ igraph_attribute_type_t type=oldrec->type;+ bsvector_t *str, *newstr;+ if (type == IGRAPH_ATTRIBUTE_STRING) {+ str=(bsvector_t*)oldrec->value;+ newstr=igraph_Calloc(1, bsvector_t);+ if (!newstr) {+ IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_CHECK(bsvector_init(newstr, 0));+ IGRAPH_FINALLY(bsvector_destroy, newstr);+ bsvector_index(str, newstr, idx);+ oldrec->value=newstr;+ bsvector_destroy(str);+ igraph_Free(str);+ IGRAPH_FINALLY_CLEAN(1);+ } else {+ IGRAPH_WARNING("Unknown edge attribute ignored");+ }+ }+ } else {+ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *val=&attr->val;+ long int valno=igraph_vector_ptr_size(val);+ long int i;++ /* New vertex attributes */+ igraph_haskell_attributes_t *new_attr=newgraph->attr;+ igraph_vector_ptr_t *new_val=&new_attr->val;+ if (igraph_vector_ptr_size(new_val) != 0) {+ IGRAPH_ERROR("Vertex attributes were already copied",+ IGRAPH_EATTRIBUTES);+ }+ IGRAPH_CHECK(igraph_vector_ptr_resize(new_val, valno));++ IGRAPH_FINALLY(igraph_haskell_attribute_permute_free, new_val);++ for (i=0; i<valno; i++) {+ igraph_attribute_record_t *oldrec=VECTOR(*val)[i];+ igraph_attribute_type_t type=oldrec->type;+ bsvector_t *str, *newstr;++ /* The record itself */+ igraph_attribute_record_t *new_rec=+ igraph_Calloc(1, igraph_attribute_record_t);+ if (!new_rec) {+ IGRAPH_ERROR("Cannot create vertex attributes", IGRAPH_ENOMEM);+ }+ new_rec->name = strdup(oldrec->name);+ new_rec->type = oldrec->type;+ VECTOR(*new_val)[i]=new_rec;++ /* The data */+ if (type == IGRAPH_ATTRIBUTE_STRING) {+ str=(bsvector_t*)oldrec->value;+ newstr=igraph_Calloc(1, bsvector_t);+ if (!newstr) {+ IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_CHECK(bsvector_init(newstr, 0));+ IGRAPH_FINALLY(bsvector_destroy, newstr);+ bsvector_index(str, newstr, idx);+ new_rec->value=newstr;+ IGRAPH_FINALLY_CLEAN(1);+ } else {+ IGRAPH_WARNING("Unknown vertex attribute ignored");+ }+ }+ }++ IGRAPH_FINALLY_CLEAN(1);+ return 0;+}++int igraph_haskell_attribute_combine_vertices(const igraph_t *graph,+ igraph_t *newgraph,+ const igraph_vector_ptr_t *merges,+ const igraph_attribute_combination_t *comb) {+ IGRAPH_ERROR("Cannot combine vertex attributes", IGRAPH_ENOMEM);+ return 1;+}++int igraph_haskell_attribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,+ igraph_vector_ptr_t *nattr) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *eal=&attr->eal;+ long int ealno=igraph_vector_ptr_size(eal);+ long int ne=igraph_vector_size(edges)/2;+ long int origlen=igraph_ecount(graph)-ne;+ long int nattrno= nattr == 0 ? 0 : igraph_vector_ptr_size(nattr);+ igraph_vector_t news;+ long int newattrs, i;++ /* First add the new attributes if any */+ newattrs=0;+ IGRAPH_VECTOR_INIT_FINALLY(&news, 0);+ for (i=0; i<nattrno; i++) {+ igraph_attribute_record_t *nattr_entry=VECTOR(*nattr)[i];+ const char *nname=nattr_entry->name;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(eal, nname, &j);+ if (!l) {+ newattrs++;+ IGRAPH_CHECK(igraph_vector_push_back(&news, i));+ } else {+ /* check types */+ if (nattr_entry->type != ((igraph_attribute_record_t*)VECTOR(*eal)[j])->type) {+ IGRAPH_ERROR("You cannot mix attribute types", IGRAPH_EINVAL);+ }+ }+ }++ /* Add NA/empty string vectors for the existing vertices */+ if (newattrs != 0) {+ for (i=0; i<newattrs; i++) {+ igraph_attribute_record_t *tmp=VECTOR(*nattr)[(long int)VECTOR(news)[i]];+ igraph_attribute_record_t *newrec=igraph_Calloc(1, igraph_attribute_record_t);+ igraph_attribute_type_t type=tmp->type;+ if (!newrec) {+ IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, newrec);+ newrec->type=type;+ newrec->name=strdup(tmp->name);+ if (!newrec->name) {+ IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, (char*)newrec->name);+ if (type==IGRAPH_ATTRIBUTE_STRING) {+ bsvector_t *newstr=igraph_Calloc(1, bsvector_t);+ if (!newstr) {+ IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, newstr);+ BSVECTOR_INIT_FINALLY(newstr, origlen);+ newrec->value=newstr;+ }+ IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, newrec));+ IGRAPH_FINALLY_CLEAN(4);+ }+ ealno=igraph_vector_ptr_size(eal);+ }++ /* Now append the new values */+ for (i=0; i<ealno; i++) {+ igraph_attribute_record_t *oldrec=VECTOR(*eal)[i];+ igraph_attribute_record_t *newrec=0;+ const char *name=oldrec->name;+ long int j;+ igraph_bool_t l=0;+ if (nattr) { l=igraph_haskell_attribute_find(nattr, name, &j); }+ if (l) {+ /* This attribute is present in nattr */+ bsvector_t *oldstr, *newstr;+ newrec=VECTOR(*nattr)[j];+ oldstr=(bsvector_t*)oldrec->value;+ newstr=(bsvector_t*)newrec->value;+ if (oldrec->type != newrec->type) {+ IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);+ }+ if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) {+ if (ne != bsvector_size(newstr)) {+ IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL);+ }+ IGRAPH_CHECK(bsvector_append(oldstr, newstr));+ } else {+ IGRAPH_WARNING("Invalid attribute type");+ }+ } else {+ /* No such attribute, append NA's */+ bsvector_t *oldstr=(bsvector_t*)oldrec->value;+ if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) {+ IGRAPH_CHECK(bsvector_resize(oldstr, origlen+ne));+ } else {+ IGRAPH_WARNING("Invalid attribute type");+ }+ }+ }++ igraph_vector_destroy(&news);+ IGRAPH_FINALLY_CLEAN(1);++ return 0;+}++int igraph_haskell_attribute_permute_edges(const igraph_t *graph,+ igraph_t *newgraph,+ const igraph_vector_t *idx) {++ if (graph == newgraph) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *eal=&attr->eal;+ long int ealno=igraph_vector_ptr_size(eal);+ long int i;++ for (i=0; i<ealno; i++) {+ igraph_attribute_record_t *oldrec=VECTOR(*eal)[i];+ igraph_attribute_type_t type=oldrec->type;+ bsvector_t *str, *newstr;+ if (type == IGRAPH_ATTRIBUTE_STRING) {+ str=(bsvector_t*)oldrec->value;+ newstr=igraph_Calloc(1, bsvector_t);+ if (!newstr) {+ IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_CHECK(bsvector_init(newstr, 0));+ IGRAPH_FINALLY(bsvector_destroy, newstr);+ bsvector_index(str, newstr, idx);+ oldrec->value=newstr;+ bsvector_destroy(str);+ igraph_Free(str);+ IGRAPH_FINALLY_CLEAN(1);+ } else {+ IGRAPH_WARNING("Unknown edge attribute ignored");+ }+ }++ } else {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *eal=&attr->eal;+ long int ealno=igraph_vector_ptr_size(eal);+ long int i;++ /* New edge attributes */+ igraph_haskell_attributes_t *new_attr=newgraph->attr;+ igraph_vector_ptr_t *new_eal=&new_attr->eal;+ IGRAPH_CHECK(igraph_vector_ptr_resize(new_eal, ealno));++ IGRAPH_FINALLY(igraph_haskell_attribute_permute_free, new_eal);++ for (i=0; i<ealno; i++) {+ igraph_attribute_record_t *oldrec=VECTOR(*eal)[i];+ igraph_attribute_type_t type=oldrec->type;+ bsvector_t *str, *newstr;++ /* The record itself */+ igraph_attribute_record_t *new_rec= igraph_Calloc(1, igraph_attribute_record_t);+ if (!new_rec) {+ IGRAPH_ERROR("Cannot create edge attributes", IGRAPH_ENOMEM);+ }+ new_rec->name = strdup(oldrec->name);+ new_rec->type = oldrec->type;+ VECTOR(*new_eal)[i] = new_rec;++ if (type == IGRAPH_ATTRIBUTE_STRING) {+ str=(bsvector_t*)oldrec->value;+ newstr=igraph_Calloc(1, bsvector_t);+ if (!newstr) {+ IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);+ }+ IGRAPH_CHECK(bsvector_init(newstr, 0));+ IGRAPH_FINALLY(bsvector_destroy, newstr);+ bsvector_index(str, newstr, idx);+ new_rec->value=newstr;+ IGRAPH_FINALLY_CLEAN(1);+ } else {+ IGRAPH_WARNING("Unknown edge attribute ignored");+ }+ }+ IGRAPH_FINALLY_CLEAN(1);+ }++ return 0;+}++int igraph_haskell_attribute_combine_edges(const igraph_t *graph,+ igraph_t *newgraph,+ const igraph_vector_ptr_t *merges,+ const igraph_attribute_combination_t *comb) {++ IGRAPH_ERROR("Cannot combine edge attributes", IGRAPH_ENOMEM);+ return 1;+}++int igraph_haskell_attribute_get_info(const igraph_t *graph,+ igraph_strvector_t *gnames,+ igraph_vector_t *gtypes,+ igraph_strvector_t *vnames,+ igraph_vector_t *vtypes,+ igraph_strvector_t *enames,+ igraph_vector_t *etypes) {++ igraph_strvector_t *names[3] = { gnames, vnames, enames };+ igraph_vector_t *types[3] = { gtypes, vtypes, etypes };+ igraph_haskell_attributes_t *at=graph->attr;+ igraph_vector_ptr_t *attr[3]={ &at->gal, &at->val, &at->eal };+ long int i,j;++ for (i=0; i<3; i++) {+ igraph_strvector_t *n=names[i];+ igraph_vector_t *t=types[i];+ igraph_vector_ptr_t *al=attr[i];+ long int len=igraph_vector_ptr_size(al);++ if (n) {+ IGRAPH_CHECK(igraph_strvector_resize(n, len));+ }+ if (t) {+ IGRAPH_CHECK(igraph_vector_resize(t, len));+ }++ for (j=0; j<len; j++) {+ igraph_attribute_record_t *rec=VECTOR(*al)[j];+ const char *name=rec->name;+ igraph_attribute_type_t type=rec->type;+ if (n) {+ IGRAPH_CHECK(igraph_strvector_set(n, j, name));+ }+ if (t) {+ VECTOR(*t)[j]=type;+ }+ }+ }++ return 0;+}++igraph_bool_t igraph_haskell_attribute_has_attr(const igraph_t *graph,+ igraph_attribute_elemtype_t type,+ const char *name) {+ igraph_haskell_attributes_t *at=graph->attr;+ igraph_vector_ptr_t *attr[3]={ &at->gal, &at->val, &at->eal };+ long int attrnum;++ switch (type) {+ case IGRAPH_ATTRIBUTE_GRAPH:+ attrnum=0;+ break;+ case IGRAPH_ATTRIBUTE_VERTEX:+ attrnum=1;+ break;+ case IGRAPH_ATTRIBUTE_EDGE:+ attrnum=2;+ break;+ default:+ IGRAPH_ERROR("Unknown attribute element type", IGRAPH_EINVAL);+ break;+ }++ return igraph_haskell_attribute_find(attr[attrnum], name, 0);+}++int igraph_haskell_attribute_gettype(const igraph_t *graph,+ igraph_attribute_type_t *type,+ igraph_attribute_elemtype_t elemtype,+ const char *name) {+ long int attrnum;+ igraph_attribute_record_t *rec;+ igraph_haskell_attributes_t *at=graph->attr;+ igraph_vector_ptr_t *attr[3]={ &at->gal, &at->val, &at->eal };+ igraph_vector_ptr_t *al;+ long int j;+ igraph_bool_t l=0;++ switch (elemtype) {+ case IGRAPH_ATTRIBUTE_GRAPH:+ attrnum=0;+ break;+ case IGRAPH_ATTRIBUTE_VERTEX:+ attrnum=1;+ break;+ case IGRAPH_ATTRIBUTE_EDGE:+ attrnum=2;+ break;+ default:+ IGRAPH_ERROR("Unknown attribute element type", IGRAPH_EINVAL);+ break;+ }++ al=attr[attrnum];+ l=igraph_haskell_attribute_find(al, name, &j);+ if (!l) {+ IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);+ }+ rec=VECTOR(*al)[j];+ *type=rec->type;++ return 0;+}++int igraph_haskell_attribute_get_numeric_graph_attr(const igraph_t *graph,+ const char *name,+ igraph_vector_t *value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++int igraph_haskell_attribute_get_bool_graph_attr(const igraph_t *graph,+ const char *name,+ igraph_vector_bool_t *value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++int igraph_haskell_attribute_get_string_graph_attr(const igraph_t *graph,+ const char *name,+ igraph_strvector_t *value_) {+ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *gal=&attr->gal;+ long int j;+ igraph_attribute_record_t *rec;+ bsvector_t *str;+ igraph_bool_t l=igraph_haskell_attribute_find(gal, name, &j);++ if (!l) {+ IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);+ }++ rec=VECTOR(*gal)[j];+ str=(bsvector_t*)rec->value;++ bsvector_t *value;+ bsvector_init(value, 1);++ IGRAPH_CHECK(bsvector_set(value, 0, BS(*str,0)));++ igraph_strvector_copy(value_, bsvector_to_strvector(value));++ return 0;+}++int igraph_haskell_attribute_get_numeric_vertex_attr(const igraph_t *graph,+ const char *name,+ igraph_vs_t vs,+ igraph_vector_t *value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++int igraph_haskell_attribute_get_bool_vertex_attr(const igraph_t *graph,+ const char *name,+ igraph_vs_t vs,+ igraph_vector_bool_t *value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++int igraph_haskell_attribute_get_string_vertex_attr(const igraph_t *graph,+ const char *name,+ igraph_vs_t vs,+ igraph_strvector_t *value_) {+ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *val=&attr->val;+ long int j;+ igraph_attribute_record_t *rec;+ bsvector_t *str;+ igraph_bool_t l=igraph_haskell_attribute_find(val, name, &j);++ if (!l) {+ IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);+ }++ bsvector_t *value;+ bsvector_init(value, 0);++ rec=VECTOR(*val)[j];+ str=(bsvector_t*)rec->value;+ if (igraph_vs_is_all(&vs)) {+ bsvector_resize(value, 0);+ IGRAPH_CHECK(bsvector_append(value, str));+ } else {+ igraph_vit_t it;+ long int i=0;+ IGRAPH_CHECK(igraph_vit_create(graph, vs, &it));+ IGRAPH_FINALLY(igraph_vit_destroy, &it);+ IGRAPH_CHECK(bsvector_resize(value, IGRAPH_VIT_SIZE(it)));+ for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {+ long int v=IGRAPH_VIT_GET(it);+ bytestring_t *s;+ bsvector_get(str, v, &s);+ IGRAPH_CHECK(bsvector_set(value, i, s));+ }+ igraph_vit_destroy(&it);+ IGRAPH_FINALLY_CLEAN(1);+ }++ igraph_strvector_copy(value_, bsvector_to_strvector(value));+ return 0;+}++int igraph_haskell_attribute_get_numeric_edge_attr(const igraph_t *graph,+ const char *name,+ igraph_es_t es,+ igraph_vector_t *value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++int igraph_haskell_attribute_get_string_edge_attr(const igraph_t *graph,+ const char *name,+ igraph_es_t es,+ igraph_strvector_t *value_) {+ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *eal=&attr->eal;+ long int j;+ igraph_attribute_record_t *rec;+ bsvector_t *str;+ igraph_bool_t l=igraph_haskell_attribute_find(eal, name, &j);++ if (!l) {+ IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL);+ }++ bsvector_t *value;+ bsvector_init(value, 1);++ rec=VECTOR(*eal)[j];+ str=(bsvector_t*)rec->value;+ if (igraph_es_is_all(&es)) {+ bsvector_resize(value, 0);+ IGRAPH_CHECK(bsvector_append(value, str));+ } else {+ igraph_eit_t it;+ long int i=0;+ IGRAPH_CHECK(igraph_eit_create(graph, es, &it));+ IGRAPH_FINALLY(igraph_eit_destroy, &it);+ IGRAPH_CHECK(bsvector_resize(value, IGRAPH_EIT_SIZE(it)));+ for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) {+ long int e=IGRAPH_EIT_GET(it);+ bytestring_t *s;+ bsvector_get(str, e, &s);+ IGRAPH_CHECK(bsvector_set(value, i, s));+ }+ igraph_eit_destroy(&it);+ IGRAPH_FINALLY_CLEAN(1);+ }++ igraph_strvector_copy(value_, bsvector_to_strvector(value));+ return 0;+}++int igraph_haskell_attribute_get_bool_edge_attr(const igraph_t *graph,+ const char *name,+ igraph_es_t es,+ igraph_vector_bool_t *value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++igraph_real_t igraph_haskell_attribute_GAN(const igraph_t *graph, const char *name) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_GAB+ * Query a boolean graph attribute.+ *+ * Returns the value of the given numeric graph attribute.+ * The attribute must exist, otherwise an error is triggered.+ * \param graph The input graph.+ * \param name The name of the attribute to query.+ * \return The value of the attribute.+ *+ * \sa \ref GAB for a simpler interface.+ *+ * Time complexity: O(Ag), the number of graph attributes.+ */+igraph_bool_t igraph_haskell_attribute_GAB(const igraph_t *graph, const char *name) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_GAS+ * Query a string graph attribute.+ *+ * Returns a <type>const</type> pointer to the string graph attribute+ * specified in \p name.+ * The attribute must exist, otherwise an error is triggered.+ * \param graph The input graph.+ * \param name The name of the attribute to query.+ * \return The value of the attribute.+ *+ * \sa \ref GAS for a simpler interface.+ *+ * Time complexity: O(Ag), the number of graph attributes.+ */+const bytestring_t* igraph_haskell_attribute_GAS(const igraph_t *graph, const char *name) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *gal=&attr->gal;+ long int j;+ igraph_attribute_record_t *rec;+ bsvector_t *str;+ igraph_bool_t l=igraph_haskell_attribute_find(gal, name, &j);++ if (!l) {+ igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);+ return 0;+ }++ rec=VECTOR(*gal)[j];+ str=(bsvector_t*)rec->value;+ return BS(*str, 0);+}++/**+ * \function igraph_haskell_attribute_VAN+ * Query a numeric vertex attribute.+ *+ * The attribute must exist, otherwise an error is triggered.+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param vid The id of the queried vertex.+ * \return The value of the attribute.+ *+ * \sa \ref VAN macro for a simpler interface.+ *+ * Time complexity: O(Av), the number of vertex attributes.+ */+igraph_real_t igraph_haskell_attribute_VAN(const igraph_t *graph, const char *name,+ igraph_integer_t vid) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_VAB+ * Query a boolean vertex attribute.+ *+ * The attribute must exist, otherwise an error is triggered.+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param vid The id of the queried vertex.+ * \return The value of the attribute.+ *+ * \sa \ref VAB macro for a simpler interface.+ *+ * Time complexity: O(Av), the number of vertex attributes.+ */+igraph_bool_t igraph_haskell_attribute_VAB(const igraph_t *graph, const char *name,+ igraph_integer_t vid) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_VAS+ * Query a string vertex attribute.+ *+ * The attribute must exist, otherwise an error is triggered.+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param vid The id of the queried vertex.+ * \return The value of the attribute.+ *+ * \sa The macro \ref VAS for a simpler interface.+ *+ * Time complexity: O(Av), the number of vertex attributes.+ */+const bytestring_t* igraph_haskell_attribute_VAS(const igraph_t *graph, const char *name,+ igraph_integer_t vid) {+ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *val=&attr->val;+ long int j;+ igraph_attribute_record_t *rec;+ bsvector_t *str;+ igraph_bool_t l=igraph_haskell_attribute_find(val, name, &j);++ if (!l) {+ igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);+ return 0;+ }++ rec=VECTOR(*val)[j];+ str=(bsvector_t*)rec->value;+ return BS(*str, (long int)vid);+}++/**+ * \function igraph_haskell_attribute_EAN+ * Query a numeric edge attribute.+ *+ * The attribute must exist, otherwise an error is triggered.+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param eid The id of the queried edge.+ * \return The value of the attribute.+ *+ * \sa \ref EAN for an easier interface.+ *+ * Time complexity: O(Ae), the number of edge attributes.+ */+igraph_real_t igraph_haskell_attribute_EAN(const igraph_t *graph, const char *name,+ igraph_integer_t eid) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_EAB+ * Query a boolean edge attribute.+ *+ * The attribute must exist, otherwise an error is triggered.+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param eid The id of the queried edge.+ * \return The value of the attribute.+ *+ * \sa \ref EAB for an easier interface.+ *+ * Time complexity: O(Ae), the number of edge attributes.+ */+igraph_bool_t igraph_haskell_attribute_EAB(const igraph_t *graph, const char *name,+ igraph_integer_t eid) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_EAS+ * Query a string edge attribute.+ *+ * The attribute must exist, otherwise an error is triggered.+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param eid The id of the queried edge.+ * \return The value of the attribute.+ *+ * \se \ref EAS if you want to type less.+ *+ * Time complexity: O(Ae), the number of edge attributes.+ */+const bytestring_t* igraph_haskell_attribute_EAS(const igraph_t *graph, const char *name,+ igraph_integer_t eid) {+ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *eal=&attr->eal;+ long int j;+ igraph_attribute_record_t *rec;+ bsvector_t *str;+ igraph_bool_t l=igraph_haskell_attribute_find(eal, name, &j);++ if (!l) {+ igraph_error("Unknown attribute", __FILE__, __LINE__, IGRAPH_EINVAL);+ return 0;+ }++ rec=VECTOR(*eal)[j];+ str=(bsvector_t*)rec->value;+ return BS(*str, (long int)eid);+}++/**+ * \function igraph_haskell_attribute_VANV+ * Query a numeric vertex attribute for many vertices+ *+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param vids The vertices to query.+ * \param result Pointer to an initialized vector, the result is+ * stored here. It will be resized, if needed.+ * \return Error code.+ *+ * Time complexity: O(v), where v is the number of vertices in 'vids'.+ */++int igraph_haskell_attribute_VANV(const igraph_t *graph, const char *name,+ igraph_vs_t vids, igraph_vector_t *result) {++ return igraph_haskell_attribute_get_numeric_vertex_attr(graph, name, vids,+ result);+}++/**+ * \function igraph_haskell_attribute_VABV+ * Query a boolean vertex attribute for many vertices+ *+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param vids The vertices to query.+ * \param result Pointer to an initialized boolean vector, the result is+ * stored here. It will be resized, if needed.+ * \return Error code.+ *+ * Time complexity: O(v), where v is the number of vertices in 'vids'.+ */++int igraph_haskell_attribute_VABV(const igraph_t *graph, const char *name,+ igraph_vs_t vids, igraph_vector_bool_t *result) {++ return igraph_haskell_attribute_get_bool_vertex_attr(graph, name, vids,+ result);+}++/**+ * \function igraph_haskell_attribute_EANV+ * Query a numeric edge attribute for many edges+ *+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param eids The edges to query.+ * \param result Pointer to an initialized vector, the result is+ * stored here. It will be resized, if needed.+ * \return Error code.+ *+ * Time complexity: O(e), where e is the number of edges in 'eids'.+ */++int igraph_haskell_attribute_EANV(const igraph_t *graph, const char *name,+ igraph_es_t eids, igraph_vector_t *result) {++ return igraph_haskell_attribute_get_numeric_edge_attr(graph, name, eids,+ result);+}++/**+ * \function igraph_haskell_attribute_EABV+ * Query a boolean edge attribute for many edges+ *+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param eids The edges to query.+ * \param result Pointer to an initialized boolean vector, the result is+ * stored here. It will be resized, if needed.+ * \return Error code.+ *+ * Time complexity: O(e), where e is the number of edges in 'eids'.+ */++int igraph_haskell_attribute_EABV(const igraph_t *graph, const char *name,+ igraph_es_t eids, igraph_vector_bool_t *result) {++ return igraph_haskell_attribute_get_bool_edge_attr(graph, name, eids,+ result);+}++/**+ * \function igraph_haskell_attribute_VASV+ * Query a string vertex attribute for many vertices+ *+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param vids The vertices to query.+ * \param result Pointer to an initialized string vector, the result+ * is stored here. It will be resized, if needed.+ * \return Error code.+ *+ * Time complexity: O(v), where v is the number of vertices in 'vids'.+ * (We assume that the string attributes have a bounded length.)+ */++int igraph_haskell_attribute_VASV(const igraph_t *graph, const char *name,+ igraph_vs_t vids, igraph_strvector_t *result) {++ return igraph_haskell_attribute_get_string_vertex_attr(graph, name, vids,+ result);+}++/**+ * \function igraph_haskell_attribute_EASV+ * Query a string edge attribute for many edges+ *+ * \param graph The input graph.+ * \param name The name of the attribute.+ * \param vids The edges to query.+ * \param result Pointer to an initialized string vector, the result+ * is stored here. It will be resized, if needed.+ * \return Error code.+ *+ * Time complexity: O(e), where e is the number of edges in+ * 'eids'. (We assume that the string attributes have a bounded length.)+ */++int igraph_haskell_attribute_EASV(const igraph_t *graph, const char *name,+ igraph_es_t eids, igraph_strvector_t *result) {++ return igraph_haskell_attribute_get_string_edge_attr(graph, name, eids,+ result);+}++/**+ * \function igraph_haskell_attribute_list+ * List all attributes+ *+ * See \ref igraph_attribute_type_t for the various attribute types.+ * \param graph The input graph.+ * \param gnames String vector, the names of the graph attributes.+ * \param gtypes Numeric vector, the types of the graph attributes.+ * \param vnames String vector, the names of the vertex attributes.+ * \param vtypes Numeric vector, the types of the vertex attributes.+ * \param enames String vector, the names of the edge attributes.+ * \param etypes Numeric vector, the types of the edge attributes.+ * \return Error code.+ *+ * Naturally, the string vector with the attribute names and the+ * numeric vector with the attribute types are in the right order,+ * i.e. the first name corresponds to the first type, etc.+ *+ * Time complexity: O(Ag+Av+Ae), the number of all attributes.+ */+int igraph_haskell_attribute_list(const igraph_t *graph,+ igraph_strvector_t *gnames, igraph_vector_t *gtypes,+ igraph_strvector_t *vnames, igraph_vector_t *vtypes,+ igraph_strvector_t *enames, igraph_vector_t *etypes) {+ return igraph_haskell_attribute_get_info(graph, gnames, gtypes, vnames, vtypes,+ enames, etypes);+}++/**+ * \function igraph_haskell_attribute_has_attr+ * Checks whether a (graph, vertex or edge) attribute exists+ *+ * \param graph The graph.+ * \param type The type of the attribute, \c IGRAPH_ATTRIBUTE_GRAPH,+ * \c IGRAPH_ATTRIBUTE_VERTEX or \c IGRAPH_ATTRIBUTE_EDGE.+ * \param name Character constant, the name of the attribute.+ * \return Logical value, TRUE if the attribute exists, FALSE otherwise.+ *+ * Time complexity: O(A), the number of (graph, vertex or edge)+ * attributes, assuming attribute names are not too long.+igraph_bool_t igraph_haskell_attribute_has_attr(const igraph_t *graph,+ igraph_attribute_elemtype_t type,+ const char *name) {+ return igraph_haskell_attribute_has_attr(graph, type, name);+}+ */++/**+ * \function igraph_haskell_attribute_GAN_set+ * Set a numeric graph attribute+ *+ * \param graph The graph.+ * \param name Name of the graph attribute. If there is no such+ * attribute yet, then it will be added.+ * \param value The (new) value of the graph attribute.+ * \return Error code.+ *+ * \se \ref SETGAN if you want to type less.+ *+ * Time complexity: O(1).+ */+int igraph_haskell_attribute_GAN_set(igraph_t *graph, const char *name,+ igraph_real_t value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_GAB_set+ * Set a boolean graph attribute+ *+ * \param graph The graph.+ * \param name Name of the graph attribute. If there is no such+ * attribute yet, then it will be added.+ * \param value The (new) value of the graph attribute.+ * \return Error code.+ *+ * \se \ref SETGAN if you want to type less.+ *+ * Time complexity: O(1).+ */+int igraph_haskell_attribute_GAB_set(igraph_t *graph, const char *name,+ igraph_bool_t value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_GAS_set+ * Set a string graph attribute.+ *+ * \param graph The graph.+ * \param name Name of the graph attribute. If there is no such+ * attribute yet, then it will be added.+ * \param value The (new) value of the graph attribute. It will be+ * copied.+ * \return Error code.+ *+ * \se \ref SETGAS if you want to type less.+ *+ * Time complexity: O(1).+ */+int igraph_haskell_attribute_GAS_set(igraph_t *graph, const char *name,+ const bytestring_t *value) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *gal=&attr->gal;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(gal, name, &j);++ if (l) {+ igraph_attribute_record_t *rec=VECTOR(*gal)[j];+ if (rec->type != IGRAPH_ATTRIBUTE_STRING) {+ IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);+ } else {+ bsvector_t *str=(bsvector_t*)rec->value;+ IGRAPH_CHECK(bsvector_set(str, 0, value));+ }+ } else {+ igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);+ bsvector_t *str;+ if (!rec) {+ IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, rec);+ rec->name=strdup(name);+ if (!rec->name) {+ IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, (char*)rec->name);+ rec->type=IGRAPH_ATTRIBUTE_STRING;+ str=igraph_Calloc(1, bsvector_t);+ if (!str) {+ IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, str);+ BSVECTOR_INIT_FINALLY(str, 1);+ IGRAPH_CHECK(bsvector_set(str, 0, value));+ rec->value=str;+ IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec));+ IGRAPH_FINALLY_CLEAN(4);+ }++ return 0;+}++/**+ * \function igraph_haskell_attribute_VAN_set+ * Set a numeric vertex attribute+ *+ * The attribute will be added if not present already. If present it+ * will be overwritten. The same \p value is set for all vertices+ * included in \p vid.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param vid Vertices for which to set the attribute.+ * \param value The (new) value of the attribute.+ * \return Error code.+ *+ * \sa \ref SETVAN for a simpler way.+ *+ * Time complexity: O(n), the number of vertices if the attribute is+ * new, O(|vid|) otherwise.+ */+int igraph_haskell_attribute_VAN_set(igraph_t *graph, const char *name,+ igraph_integer_t vid, igraph_real_t value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_VAB_set+ * Set a boolean vertex attribute+ *+ * The attribute will be added if not present already. If present it+ * will be overwritten. The same \p value is set for all vertices+ * included in \p vid.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param vid Vertices for which to set the attribute.+ * \param value The (new) value of the attribute.+ * \return Error code.+ *+ * \sa \ref SETVAB for a simpler way.+ *+ * Time complexity: O(n), the number of vertices if the attribute is+ * new, O(|vid|) otherwise.+ */+int igraph_haskell_attribute_VAB_set(igraph_t *graph, const char *name,+ igraph_integer_t vid, igraph_bool_t value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_VAS_set+ * Set a string vertex attribute+ *+ * The attribute will be added if not present already. If present it+ * will be overwritten. The same \p value is set for all vertices+ * included in \p vid.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param vid Vertices for which to set the attribute.+ * \param value The (new) value of the attribute.+ * \return Error code.+ *+ * \sa \ref SETVAS for a simpler way.+ *+ * Time complexity: O(n*l), n is the number of vertices, l is the+ * length of the string to set. If the attribute if not new then only+ * O(|vid|*l).+ */+int igraph_haskell_attribute_VAS_set(igraph_t *graph, const char *name,+ igraph_integer_t vid, const bytestring_t *value) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *val=&attr->val;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(val, name, &j);++ if (l) {+ igraph_attribute_record_t *rec=VECTOR(*val)[j];+ if (rec->type != IGRAPH_ATTRIBUTE_STRING) {+ IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);+ } else {+ bsvector_t *str=(bsvector_t*)rec->value;+ IGRAPH_CHECK(bsvector_set(str, vid, value));+ }+ } else {+ igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);+ bsvector_t *str;+ if (!rec) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, rec);+ rec->name=strdup(name);+ if (!rec->name) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, (char*)rec->name);+ rec->type=IGRAPH_ATTRIBUTE_STRING;+ str=igraph_Calloc(1, bsvector_t);+ if (!str) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, str);+ BSVECTOR_INIT_FINALLY(str, igraph_vcount(graph));+ IGRAPH_CHECK(bsvector_set(str, vid, value));+ rec->value=str;+ IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));+ IGRAPH_FINALLY_CLEAN(4);+ }++ return 0;+}++/**+ * \function igraph_haskell_attribute_EAN_set+ * Set a numeric edge attribute+ *+ * The attribute will be added if not present already. If present it+ * will be overwritten. The same \p value is set for all edges+ * included in \p vid.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param eid Edges for which to set the attribute.+ * \param value The (new) value of the attribute.+ * \return Error code.+ *+ * \sa \ref SETEAN for a simpler way.+ *+ * Time complexity: O(e), the number of edges if the attribute is+ * new, O(|eid|) otherwise.+ */+int igraph_haskell_attribute_EAN_set(igraph_t *graph, const char *name,+ igraph_integer_t eid, igraph_real_t value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_EAB_set+ * Set a boolean edge attribute+ *+ * The attribute will be added if not present already. If present it+ * will be overwritten. The same \p value is set for all edges+ * included in \p vid.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param eid Edges for which to set the attribute.+ * \param value The (new) value of the attribute.+ * \return Error code.+ *+ * \sa \ref SETEAB for a simpler way.+ *+ * Time complexity: O(e), the number of edges if the attribute is+ * new, O(|eid|) otherwise.+ */+int igraph_haskell_attribute_EAB_set(igraph_t *graph, const char *name,+ igraph_integer_t eid, igraph_bool_t value) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_EAS_set+ * Set a string edge attribute+ *+ * The attribute will be added if not present already. If present it+ * will be overwritten. The same \p value is set for all edges+ * included in \p vid.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param eid Edges for which to set the attribute.+ * \param value The (new) value of the attribute.+ * \return Error code.+ *+ * \sa \ref SETEAS for a simpler way.+ *+ * Time complexity: O(e*l), n is the number of edges, l is the+ * length of the string to set. If the attribute if not new then only+ * O(|eid|*l).+ */+int igraph_haskell_attribute_EAS_set(igraph_t *graph, const char *name,+ igraph_integer_t eid, const bytestring_t *value) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *eal=&attr->eal;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(eal, name, &j);++ if (l) {+ igraph_attribute_record_t *rec=VECTOR(*eal)[j];+ if (rec->type != IGRAPH_ATTRIBUTE_STRING) {+ IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL);+ } else {+ bsvector_t *str=(bsvector_t*)rec->value;+ IGRAPH_CHECK(bsvector_set(str, eid, value));+ }+ } else {+ igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);+ bsvector_t *str;+ if (!rec) {+ IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, rec);+ rec->name=strdup(name);+ if (!rec->name) {+ IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, (char*)rec->name);+ rec->type=IGRAPH_ATTRIBUTE_STRING;+ str=igraph_Calloc(1, bsvector_t);+ if (!str) {+ IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, str);+ BSVECTOR_INIT_FINALLY(str, igraph_ecount(graph));+ IGRAPH_CHECK(bsvector_set(str, eid, value));+ rec->value=str;+ IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));+ IGRAPH_FINALLY_CLEAN(4);+ }++ return 0;+}++/**+ * \function igraph_haskell_attribute_VAN_setv+ * Set a numeric vertex attribute for all vertices.+ *+ * The attribute will be added if not present yet.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param v The new attribute values. The length of this vector must+ * match the number of vertices.+ * \return Error code.+ *+ * \sa \ref SETVANV for a simpler way.+ *+ * Time complexity: O(n), the number of vertices.+ */++int igraph_haskell_attribute_VAN_setv(igraph_t *graph, const char *name,+ const igraph_vector_t *v) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}+/**+ * \function igraph_haskell_attribute_VAB_setv+ * Set a boolean vertex attribute for all vertices.+ *+ * The attribute will be added if not present yet.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param v The new attribute values. The length of this boolean vector must+ * match the number of vertices.+ * \return Error code.+ *+ * \sa \ref SETVANV for a simpler way.+ *+ * Time complexity: O(n), the number of vertices.+ */++int igraph_haskell_attribute_VAB_setv(igraph_t *graph, const char *name,+ const igraph_vector_bool_t *v) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_VAS_setv+ * Set a string vertex attribute for all vertices.+ *+ * The attribute will be added if not present yet.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param sv String vector, the new attribute values. The length of this vector must+ * match the number of vertices.+ * \return Error code.+ *+ * \sa \ref SETVASV for a simpler way.+ *+ * Time complexity: O(n+l), n is the number of vertices, l is the+ * total length of the strings.+ */+int igraph_haskell_attribute_VAS_setv(igraph_t *graph, const char *name,+ const bsvector_t *sv) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *val=&attr->val;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(val, name, &j);++ /* Check length first */+ if (bsvector_size(sv) != igraph_vcount(graph)) {+ IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL);+ }++ if (l) {+ /* Already present, check type */+ igraph_attribute_record_t *rec=VECTOR(*val)[j];+ bsvector_t *str=(bsvector_t *)rec->value;+ if (rec->type != IGRAPH_ATTRIBUTE_STRING) {+ IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);+ }+ bsvector_clear(str);+ IGRAPH_CHECK(bsvector_append(str, sv));+ } else {+ /* Add it */+ igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);+ bsvector_t *str;+ if (!rec) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, rec);+ rec->type=IGRAPH_ATTRIBUTE_STRING;+ rec->name=strdup(name);+ if (!rec->name) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, (char*)rec->name);+ str=igraph_Calloc(1, bsvector_t);+ if (!str) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, str);+ rec->value=str;+ IGRAPH_CHECK(bsvector_copy(str, sv));+ IGRAPH_FINALLY(bsvector_destroy, str);+ IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));+ IGRAPH_FINALLY_CLEAN(4);+ }++ return 0;+}++/**+ * \function igraph_haskell_attribute_EAN_setv+ * Set a numeric edge attribute for all vertices.+ *+ * The attribute will be added if not present yet.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param v The new attribute values. The length of this vector must+ * match the number of edges.+ * \return Error code.+ *+ * \sa \ref SETEANV for a simpler way.+ *+ * Time complexity: O(e), the number of edges.+ */+int igraph_haskell_attribute_EAN_setv(igraph_t *graph, const char *name,+ const igraph_vector_t *v) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_EAB_setv+ * Set a boolean edge attribute for all vertices.+ *+ * The attribute will be added if not present yet.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param v The new attribute values. The length of this vector must+ * match the number of edges.+ * \return Error code.+ *+ * \sa \ref SETEABV for a simpler way.+ *+ * Time complexity: O(e), the number of edges.+ */+int igraph_haskell_attribute_EAB_setv(igraph_t *graph, const char *name,+ const igraph_vector_bool_t *v) {+ IGRAPH_ERROR("Not implemented", IGRAPH_ENOMEM);+ return 1;+}++/**+ * \function igraph_haskell_attribute_EAS_setv+ * Set a string edge attribute for all vertices.+ *+ * The attribute will be added if not present yet.+ * \param graph The graph.+ * \param name Name of the attribute.+ * \param sv String vector, the new attribute values. The length of this vector must+ * match the number of edges.+ * \return Error code.+ *+ * \sa \ref SETEASV for a simpler way.+ *+ * Time complexity: O(e+l), e is the number of edges, l is the+ * total length of the strings.+ */+int igraph_haskell_attribute_EAS_setv(igraph_t *graph, const char *name,+ const bsvector_t *sv) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *eal=&attr->eal;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(eal, name, &j);++ /* Check length first */+ if (bsvector_size(sv) != igraph_ecount(graph)) {+ IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL);+ }++ if (l) {+ /* Already present, check type */+ igraph_attribute_record_t *rec=VECTOR(*eal)[j];+ bsvector_t *str=(bsvector_t *)rec->value;+ if (rec->type != IGRAPH_ATTRIBUTE_STRING) {+ IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL);+ }+ bsvector_clear(str);+ IGRAPH_CHECK(bsvector_append(str, sv));+ } else {+ /* Add it */+ igraph_attribute_record_t *rec=igraph_Calloc(1, igraph_attribute_record_t);+ bsvector_t *str;+ if (!rec) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, rec);+ rec->type=IGRAPH_ATTRIBUTE_STRING;+ rec->name=strdup(name);+ if (!rec->name) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, (char*)rec->name);+ str=igraph_Calloc(1, bsvector_t);+ if (!str) {+ IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM);+ }+ IGRAPH_FINALLY(igraph_free, str);+ rec->value=str;+ IGRAPH_CHECK(bsvector_copy(str, sv));+ IGRAPH_FINALLY(bsvector_destroy, str);+ IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec));+ IGRAPH_FINALLY_CLEAN(4);+ }++ return 0;+}++void igraph_haskell_attribute_free_rec(igraph_attribute_record_t *rec) {++ if (rec->type==IGRAPH_ATTRIBUTE_NUMERIC) {+ igraph_vector_t *num=(igraph_vector_t*)rec->value;+ igraph_vector_destroy(num);+ } else if (rec->type==IGRAPH_ATTRIBUTE_STRING) {+ bsvector_t *str=(bsvector_t*)rec->value;+ bsvector_destroy(str);+ } else if (rec->type==IGRAPH_ATTRIBUTE_BOOLEAN) {+ igraph_vector_bool_t *boolvec=(igraph_vector_bool_t*)rec->value;+ igraph_vector_bool_destroy(boolvec);+ }+ igraph_Free(rec->name);+ igraph_Free(rec->value);+ igraph_Free(rec);+}++/**+ * \function igraph_haskell_attribute_remove_g+ * Remove a graph attribute+ *+ * \param graph The graph object.+ * \param name Name of the graph attribute to remove.+ *+ * \sa \ref DELGA for a simpler way.+ *+ */+void igraph_haskell_attribute_remove_g(igraph_t *graph, const char *name) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *gal=&attr->gal;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(gal, name, &j);++ if (l) {+ igraph_haskell_attribute_free_rec(VECTOR(*gal)[j]);+ igraph_vector_ptr_remove(gal, j);+ } else {+ IGRAPH_WARNING("Cannot remove non-existent graph attribute");+ }+}++/**+ * \function igraph_haskell_attribute_remove_v+ * Remove a vertex attribute+ *+ * \param graph The graph object.+ * \param name Name of the vertex attribute to remove.+ *+ * \sa \ref DELVA for a simpler way.+ *+ */+void igraph_haskell_attribute_remove_v(igraph_t *graph, const char *name) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *val=&attr->val;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(val, name, &j);++ if (l) {+ igraph_haskell_attribute_free_rec(VECTOR(*val)[j]);+ igraph_vector_ptr_remove(val, j);+ } else {+ IGRAPH_WARNING("Cannot remove non-existent graph attribute");+ }+}++/**+ * \function igraph_haskell_attribute_remove_e+ * Remove an edge attribute+ *+ * \param graph The graph object.+ * \param name Name of the edge attribute to remove.+ *+ * \sa \ref DELEA for a simpler way.+ *+ */+void igraph_haskell_attribute_remove_e(igraph_t *graph, const char *name) {++ igraph_haskell_attributes_t *attr=graph->attr;+ igraph_vector_ptr_t *eal=&attr->eal;+ long int j;+ igraph_bool_t l=igraph_haskell_attribute_find(eal, name, &j);++ if (l) {+ igraph_haskell_attribute_free_rec(VECTOR(*eal)[j]);+ igraph_vector_ptr_remove(eal, j);+ } else {+ IGRAPH_WARNING("Cannot remove non-existent graph attribute");+ }+}++/**+ * \function igraph_haskell_attribute_remove_all+ * Remove all graph/vertex/edge attributes+ *+ * \param graph The graph object.+ * \param g Boolean, whether to remove graph attributes.+ * \param v Boolean, whether to remove vertex attributes.+ * \param e Boolean, whether to remove edge attributes.+ *+ * \sa \ref DELGAS, \ref DELVAS, \ref DELEAS, \ref DELALL for simpler+ * ways.+ */+void igraph_haskell_attribute_remove_all(igraph_t *graph, igraph_bool_t g,+ igraph_bool_t v, igraph_bool_t e) {++ igraph_haskell_attributes_t *attr=graph->attr;++ if (g) {+ igraph_vector_ptr_t *gal=&attr->gal;+ long int i, n=igraph_vector_ptr_size(gal);+ for (i=0;i<n;i++) {+ igraph_haskell_attribute_free_rec(VECTOR(*gal)[i]);+ }+ igraph_vector_ptr_clear(gal);+ }+ if (v) {+ igraph_vector_ptr_t *val=&attr->val;+ long int i, n=igraph_vector_ptr_size(val);+ for (i=0;i<n;i++) {+ igraph_haskell_attribute_free_rec(VECTOR(*val)[i]);+ }+ igraph_vector_ptr_clear(val);+ }+ if (e) {+ igraph_vector_ptr_t *eal=&attr->eal;+ long int i, n=igraph_vector_ptr_size(eal);+ for (i=0;i<n;i++) {+ igraph_haskell_attribute_free_rec(VECTOR(*eal)[i]);+ }+ igraph_vector_ptr_clear(eal);+ }+}
+ cbits/haskell_igraph.c view
@@ -0,0 +1,28 @@+#include <igraph/igraph.h>+#include "haskell_attributes.h"++const igraph_attribute_table_t igraph_haskell_attribute_table={+ &igraph_haskell_attribute_init, &igraph_haskell_attribute_destroy,+ &igraph_haskell_attribute_copy, &igraph_haskell_attribute_add_vertices,+ &igraph_haskell_attribute_permute_vertices,+ &igraph_haskell_attribute_combine_vertices, &igraph_haskell_attribute_add_edges,+ &igraph_haskell_attribute_permute_edges,+ &igraph_haskell_attribute_combine_edges,+ &igraph_haskell_attribute_get_info,+ &igraph_haskell_attribute_has_attr, &igraph_haskell_attribute_gettype,+ &igraph_haskell_attribute_get_numeric_graph_attr,+ &igraph_haskell_attribute_get_string_graph_attr,+ &igraph_haskell_attribute_get_bool_graph_attr,+ &igraph_haskell_attribute_get_numeric_vertex_attr,+ &igraph_haskell_attribute_get_string_vertex_attr,+ &igraph_haskell_attribute_get_bool_vertex_attr,+ &igraph_haskell_attribute_get_numeric_edge_attr,+ &igraph_haskell_attribute_get_string_edge_attr,+ &igraph_haskell_attribute_get_bool_edge_attr+};++void haskelligraph_init()+{+ /* attach attribute table */+ igraph_i_set_attribute_table(&igraph_haskell_attribute_table);+}
− cbits/haskelligraph.c
@@ -1,36 +0,0 @@-#include <igraph/igraph.h>--igraph_integer_t igraph_get_eid_(igraph_t* graph, igraph_integer_t pfrom, igraph_integer_t pto,- igraph_bool_t directed, igraph_bool_t error)-{- igraph_integer_t eid;- igraph_get_eid(graph, &eid, pfrom, pto, directed, error);- return eid;-}--char** igraph_strvector_get_(igraph_strvector_t* s, long int i)-{- char** x = (char**) malloc (sizeof(char*));- igraph_strvector_get(s, i, x);- return x;-}--igraph_arpack_options_t* igraph_arpack_new()-{- igraph_arpack_options_t *arpack = (igraph_arpack_options_t*) malloc(sizeof(igraph_arpack_options_t));- igraph_arpack_options_init(arpack);- return arpack;-}--void igraph_arpack_destroy(igraph_arpack_options_t* arpack)-{- if (arpack)- free(arpack);- arpack = NULL;-}--void haskelligraph_init()-{- /* attach attribute table */- igraph_i_set_attribute_table(&igraph_cattribute_table);-}
− cbits/haskelligraph.h
@@ -1,17 +0,0 @@-#ifndef HASKELL_IGRAPH-#define HASKELL_IGRAPH--#include <igraph/igraph.h>--igraph_integer_t igraph_get_eid_(igraph_t* graph, igraph_integer_t pfrom, igraph_integer_t pto,- igraph_bool_t directed, igraph_bool_t error);--char** igraph_strvector_get_(igraph_strvector_t* s, long int i);--igraph_arpack_options_t* igraph_arpack_new();--void igraph_arpack_destroy(igraph_arpack_options_t* arpack);--void haskelligraph_init();--#endif
haskell-igraph.cabal view
@@ -1,20 +1,23 @@--- Initial igraph-bindings.cabal generated by cabal init. For further--- documentation, see http://haskell.org/cabal/users-guide/- name: haskell-igraph-version: 0.3.0-synopsis: Imcomplete igraph bindings-description: This is an attempt to create a complete bindings for the- igraph<"http://igraph.org/c/"> library.+version: 0.4.0+synopsis: Haskell interface of the igraph library.+description: igraph<"http://igraph.org/c/"> is a library for creating+ and manipulating large graphs. This package provides the Haskell+ interface of igraph. license: MIT license-file: LICENSE author: Kai Zhang maintainer: kai@kzhang.org-copyright: (c) 2016 Kai Zhang+copyright: (c) 2016-2018 Kai Zhang category: Math build-type: Simple cabal-version: >=1.24-extra-source-files: cbits/haskelligraph.h+extra-source-files:+ include/haskell_igraph.h+ include/bytestring.h+ include/haskell_attributes.h+ README.md+ ChangeLog.md Flag graphics Description: Enable graphics output@@ -22,6 +25,18 @@ library exposed-modules:+ IGraph+ IGraph.Types+ IGraph.Mutable+ IGraph.Clique+ IGraph.Structure+ IGraph.Isomorphism+ IGraph.Community+ IGraph.Read+ IGraph.Motif+ IGraph.Layout+ IGraph.Generators+ IGraph.Exporter.GEXF IGraph.Internal.Initialization IGraph.Internal.Constants IGraph.Internal.Arpack@@ -35,18 +50,10 @@ IGraph.Internal.Clique IGraph.Internal.Community IGraph.Internal.Layout- IGraph- IGraph.Mutable- IGraph.Clique- IGraph.Structure- IGraph.Isomorphism- IGraph.Community- IGraph.Read- IGraph.Motif- IGraph.Layout- IGraph.Generators- IGraph.Exporter.GEXF + other-modules:+ IGraph.Internal.C2HS+ if flag(graphics) exposed-modules: IGraph.Exporter.Graphics @@ -54,11 +61,13 @@ build-depends: diagrams-lib, diagrams-cairo build-depends:- base >=4.0 && <5.0- , binary- , bytestring >=0.9- , bytestring-lexing >=0.5+ base >= 4.0 && < 5.0+ , bytestring >= 0.9+ , bytestring-lexing >= 0.5+ , cereal+ , cereal-conduit , colour+ , conduit >= 1.3.0 , primitive , unordered-containers , hashable@@ -70,8 +79,11 @@ hs-source-dirs: src default-language: Haskell2010 build-tools: c2hs >=0.25.0- c-sources: cbits/haskelligraph.c- include-dirs: cbits+ c-sources:+ cbits/haskell_igraph.c+ cbits/haskell_attributes.c+ cbits/bytestring.c+ include-dirs: include test-suite tests type: exitcode-stdio-1.0@@ -79,6 +91,7 @@ main-is: test.hs other-modules: Test.Basic+ Test.Attributes Test.Structure Test.Isomorphism Test.Motif@@ -88,6 +101,8 @@ build-depends: base , haskell-igraph+ , cereal+ , conduit >= 1.3.0 , data-ordlist , matrices , tasty
+ include/bytestring.h view
@@ -0,0 +1,111 @@+#ifndef HASKELL_IGRAPH_BYTESTRING+#define HASKELL_IGRAPH_BYTESTRING++#include <igraph/igraph.h>++typedef struct bytestring_t {+ unsigned long int len;+ char *value;+} bytestring_t;++typedef struct bsvector_t {+ bytestring_t **data;+ long int len;+} bsvector_t;++#define BSVECTOR_INIT_FINALLY(v, size) \+ do { IGRAPH_CHECK(bsvector_init(v, size)); \+ IGRAPH_FINALLY( (igraph_finally_func_t*) bsvector_destroy, v); } while (0)++/**+ * \define STR+ * Indexing string vectors+ *+ * This is a macro which allows to query the elements of a string vector in+ * simpler way than \ref igraph_strvector_get(). Note this macro cannot be+ * used to set an element, for that use \ref igraph_strvector_set().+ * \param sv The string vector+ * \param i The the index of the element.+ * \return The element at position \p i.+ *+ * Time complexity: O(1).+ */+#define BS(sv,i) ((const bytestring_t *)((sv).data[(i)]))++int bsvector_init(bsvector_t *sv, long int len);++void bsvector_destroy(bsvector_t *sv);++void bsvector_get(const bsvector_t *sv, long int idx, bytestring_t **value);++int bsvector_set(bsvector_t *sv, long int idx, const bytestring_t *value);++void bsvector_remove_section(bsvector_t *v, long int from, long int to);++void bsvector_remove(bsvector_t *v, long int elem);++/*+void bsvector_move_interval(bsvector_t *v, long int begin,+ long int end, long int to) {+ long int i;+ assert(v != 0);+ assert(v->data != 0);+ for (i=to; i<to+end-begin; i++) {+ if (v->data[i] != 0) {+ destroy_bytestring(v->data[i]);+ }+ }+ for (i=0; i<end-begin; i++) {+ if (v->data[begin+i] != 0) {+ size_t len=strlen(v->data[begin+i])+1;+ v->data[to+i]=igraph_Calloc(len, char);+ memcpy(v->data[to+i], v->data[begin+i], sizeof(char)*len);+ }+ }+}+*/++int bsvector_copy(bsvector_t *to, const bsvector_t *from);++int bsvector_append(bsvector_t *to, const bsvector_t *from);++void bsvector_clear(bsvector_t *sv);++int bsvector_resize(bsvector_t* v, long int newsize);++/**+ * \ingroup strvector+ * \function igraph_strvector_permdelete+ * \brief Removes elements from a string vector (for internal use)+ */++void bsvector_permdelete(bsvector_t *v, const igraph_vector_t *index,+ long int nremove);++/**+ * \ingroup strvector+ * \function igraph_strvector_remove_negidx+ * \brief Removes elements from a string vector (for internal use)+ */++void bsvector_remove_negidx(bsvector_t *v, const igraph_vector_t *neg,+ long int nremove);++int bsvector_index(const bsvector_t *v, bsvector_t *newv,+ const igraph_vector_t *idx);++long int bsvector_size(const bsvector_t *sv);++bytestring_t* new_bytestring(int n);++void destroy_bytestring(bytestring_t* str);++char* bytestring_to_char(bytestring_t* from);++bytestring_t* char_to_bytestring(char* from);++igraph_strvector_t* bsvector_to_strvector(bsvector_t* from);++bsvector_t* strvector_to_bsvector(igraph_strvector_t* from);++#endif
+ include/haskell_attributes.h view
@@ -0,0 +1,218 @@+#ifndef HASKELL_IGRAPH_ATTRIBUTE+#define HASKELL_IGRAPH_ATTRIBUTE++#include "igraph/igraph.h"+#include "bytestring.h"++#include <string.h>++igraph_bool_t igraph_haskell_attribute_find(const igraph_vector_ptr_t *ptrvec,+ const char *name, long int *idx);++typedef struct igraph_haskell_attributes_t {+ igraph_vector_ptr_t gal;+ igraph_vector_ptr_t val;+ igraph_vector_ptr_t eal;+} igraph_haskell_attributes_t;++int igraph_haskell_attributes_copy_attribute_record(igraph_attribute_record_t **newrec,+ const igraph_attribute_record_t *rec);+++int igraph_haskell_attribute_init(igraph_t *graph, igraph_vector_ptr_t *attr);++void igraph_haskell_attribute_destroy(igraph_t *graph);++void igraph_haskell_attribute_copy_free(igraph_haskell_attributes_t *attr);++int igraph_haskell_attribute_copy(igraph_t *to, const igraph_t *from,+ igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea);++int igraph_haskell_attribute_add_vertices(igraph_t *graph, long int nv,+ igraph_vector_ptr_t *nattr);++void igraph_haskell_attribute_permute_free(igraph_vector_ptr_t *v);++int igraph_haskell_attribute_permute_vertices(const igraph_t *graph,+ igraph_t *newgraph,+ const igraph_vector_t *idx);++int igraph_haskell_attribute_combine_vertices(const igraph_t *graph,+ igraph_t *newgraph,+ const igraph_vector_ptr_t *merges,+ const igraph_attribute_combination_t *comb);++int igraph_haskell_attribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,+ igraph_vector_ptr_t *nattr);++int igraph_haskell_attribute_permute_edges(const igraph_t *graph,+ igraph_t *newgraph,+ const igraph_vector_t *idx);++int igraph_haskell_attribute_combine_edges(const igraph_t *graph,+ igraph_t *newgraph,+ const igraph_vector_ptr_t *merges,+ const igraph_attribute_combination_t *comb);++int igraph_haskell_attribute_get_info(const igraph_t *graph,+ igraph_strvector_t *gnames,+ igraph_vector_t *gtypes,+ igraph_strvector_t *vnames,+ igraph_vector_t *vtypes,+ igraph_strvector_t *enames,+ igraph_vector_t *etypes);++igraph_bool_t igraph_haskell_attribute_has_attr(const igraph_t *graph,+ igraph_attribute_elemtype_t type,+ const char *name);++int igraph_haskell_attribute_gettype(const igraph_t *graph,+ igraph_attribute_type_t *type,+ igraph_attribute_elemtype_t elemtype,+ const char *name);++int igraph_haskell_attribute_get_numeric_graph_attr(const igraph_t *graph,+ const char *name,+ igraph_vector_t *value);++int igraph_haskell_attribute_get_bool_graph_attr(const igraph_t *graph,+ const char *name,+ igraph_vector_bool_t *value);++int igraph_haskell_attribute_get_string_graph_attr(const igraph_t *graph,+ const char *name,+ igraph_strvector_t *value_);++int igraph_haskell_attribute_get_numeric_vertex_attr(const igraph_t *graph,+ const char *name,+ igraph_vs_t vs,+ igraph_vector_t *value);++int igraph_haskell_attribute_get_bool_vertex_attr(const igraph_t *graph,+ const char *name,+ igraph_vs_t vs,+ igraph_vector_bool_t *value);++int igraph_haskell_attribute_get_string_vertex_attr(const igraph_t *graph,+ const char *name,+ igraph_vs_t vs,+ igraph_strvector_t *value_);++int igraph_haskell_attribute_get_numeric_edge_attr(const igraph_t *graph,+ const char *name,+ igraph_es_t es,+ igraph_vector_t *value);++int igraph_haskell_attribute_get_string_edge_attr(const igraph_t *graph,+ const char *name,+ igraph_es_t es,+ igraph_strvector_t *value_);++int igraph_haskell_attribute_get_bool_edge_attr(const igraph_t *graph,+ const char *name,+ igraph_es_t es,+ igraph_vector_bool_t *value);++igraph_real_t igraph_haskell_attribute_GAN(const igraph_t *graph, const char *name);++igraph_bool_t igraph_haskell_attribute_GAB(const igraph_t *graph, const char *name);++const bytestring_t* igraph_haskell_attribute_GAS(const igraph_t *graph, const char *name);++igraph_real_t igraph_haskell_attribute_VAN(const igraph_t *graph, const char *name,+ igraph_integer_t vid);++igraph_bool_t igraph_haskell_attribute_VAB(const igraph_t *graph, const char *name,+ igraph_integer_t vid);++const bytestring_t* igraph_haskell_attribute_VAS(const igraph_t *graph, const char *name,+ igraph_integer_t vid);++igraph_real_t igraph_haskell_attribute_EAN(const igraph_t *graph, const char *name,+ igraph_integer_t eid);++igraph_bool_t igraph_haskell_attribute_EAB(const igraph_t *graph, const char *name,+ igraph_integer_t eid);++const bytestring_t* igraph_haskell_attribute_EAS(const igraph_t *graph, const char *name,+ igraph_integer_t eid);++int igraph_haskell_attribute_VANV(const igraph_t *graph, const char *name,+ igraph_vs_t vids, igraph_vector_t *result);++int igraph_haskell_attribute_VABV(const igraph_t *graph, const char *name,+ igraph_vs_t vids, igraph_vector_bool_t *result);++int igraph_haskell_attribute_EANV(const igraph_t *graph, const char *name,+ igraph_es_t eids, igraph_vector_t *result);++int igraph_haskell_attribute_EABV(const igraph_t *graph, const char *name,+ igraph_es_t eids, igraph_vector_bool_t *result);++int igraph_haskell_attribute_VASV(const igraph_t *graph, const char *name,+ igraph_vs_t vids, igraph_strvector_t *result);++int igraph_haskell_attribute_EASV(const igraph_t *graph, const char *name,+ igraph_es_t eids, igraph_strvector_t *result);++int igraph_haskell_attribute_list(const igraph_t *graph,+ igraph_strvector_t *gnames, igraph_vector_t *gtypes,+ igraph_strvector_t *vnames, igraph_vector_t *vtypes,+ igraph_strvector_t *enames, igraph_vector_t *etypes);++int igraph_haskell_attribute_GAN_set(igraph_t *graph, const char *name,+ igraph_real_t value);++int igraph_haskell_attribute_GAB_set(igraph_t *graph, const char *name,+ igraph_bool_t value);++int igraph_haskell_attribute_GAS_set(igraph_t *graph, const char *name,+ const bytestring_t *value);++int igraph_haskell_attribute_VAN_set(igraph_t *graph, const char *name,+ igraph_integer_t vid, igraph_real_t value);++int igraph_haskell_attribute_VAB_set(igraph_t *graph, const char *name,+ igraph_integer_t vid, igraph_bool_t value);++int igraph_haskell_attribute_VAS_set(igraph_t *graph, const char *name,+ igraph_integer_t vid, const bytestring_t *value);++int igraph_haskell_attribute_EAN_set(igraph_t *graph, const char *name,+ igraph_integer_t eid, igraph_real_t value);++int igraph_haskell_attribute_EAB_set(igraph_t *graph, const char *name,+ igraph_integer_t eid, igraph_bool_t value);++int igraph_haskell_attribute_EAS_set(igraph_t *graph, const char *name,+ igraph_integer_t eid, const bytestring_t *value);++int igraph_haskell_attribute_VAN_setv(igraph_t *graph, const char *name,+ const igraph_vector_t *v);++int igraph_haskell_attribute_VAB_setv(igraph_t *graph, const char *name,+ const igraph_vector_bool_t *v);++int igraph_haskell_attribute_VAS_setv(igraph_t *graph, const char *name,+ const bsvector_t *sv);++int igraph_haskell_attribute_EAN_setv(igraph_t *graph, const char *name,+ const igraph_vector_t *v);++int igraph_haskell_attribute_EAB_setv(igraph_t *graph, const char *name,+ const igraph_vector_bool_t *v);++int igraph_haskell_attribute_EAS_setv(igraph_t *graph, const char *name,+ const bsvector_t *sv);++void igraph_haskell_attribute_free_rec(igraph_attribute_record_t *rec);++void igraph_haskell_attribute_remove_g(igraph_t *graph, const char *name);++void igraph_haskell_attribute_remove_v(igraph_t *graph, const char *name);++void igraph_haskell_attribute_remove_e(igraph_t *graph, const char *name);++void igraph_haskell_attribute_remove_all(igraph_t *graph, igraph_bool_t g,+ igraph_bool_t v, igraph_bool_t e);+#endif
+ include/haskell_igraph.h view
@@ -0,0 +1,8 @@+#ifndef HASKELL_IGRAPH+#define HASKELL_IGRAPH++#include <igraph/igraph.h>++void haskelligraph_init();++#endif
src/IGraph.hs view
@@ -1,12 +1,15 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} module IGraph- ( LGraph(..)+ ( Graph(..)+ , LGraph(..) , U(..) , D(..)- , Graph(..)+ , decodeC+ , empty , mkGraph , fromLabeledEdges+ , fromLabeledEdges' , unsafeFreeze , freeze@@ -26,108 +29,95 @@ , emap ) where +import Conduit import Control.Arrow ((***))-import Control.Monad (forM_, liftM)+import Control.Monad (forM, forM_, liftM, replicateM,+ unless) import Control.Monad.Primitive import Control.Monad.ST (runST)-import Data.Binary+import qualified Data.ByteString as B+import Data.Conduit.Cereal import Data.Hashable (Hashable) import qualified Data.HashMap.Strict as M-import qualified Data.HashSet as S+import qualified Data.HashSet as S+import Data.List (sortBy) import Data.Maybe+import Data.Ord (comparing)+import Data.Serialize+import Foreign (castPtr, with) import System.IO.Unsafe (unsafePerformIO) import IGraph.Internal.Attribute import IGraph.Internal.Constants+import IGraph.Internal.Data import IGraph.Internal.Graph import IGraph.Internal.Selector import IGraph.Mutable--type Node = Int-type Edge = (Node, Node)---- | graph with labeled nodes and edges-data LGraph d v e = LGraph- { _graph :: IGraphPtr- , _labelToNode :: M.HashMap v [Node]- }--instance ( Binary v, Hashable v, Read v, Show v, Eq v- , Binary e, Read e, Show e, Graph d) => Binary (LGraph d v e) where- put gr = do- put nlabs- put es- put elabs- where- nlabs = map (nodeLab gr) $ nodes gr- es = edges gr- elabs = map (edgeLab gr) es- get = do- nlabs <- get- es <- get- elabs <- get- return $ mkGraph nlabs $ zip es elabs+import IGraph.Types class MGraph d => Graph d where+ -- | Graph is directed or not. isDirected :: LGraph d v e -> Bool isD :: d -> Bool + -- | Return the number of nodes in a graph. nNodes :: LGraph d v e -> Int- nNodes (LGraph g _) = igraphVcount g+ nNodes (LGraph g _) = unsafePerformIO $ igraphVcount g {-# INLINE nNodes #-} - nodes :: LGraph d v e -> [Int]+ -- | Return all nodes. @nodes gr == [0 .. nNodes gr - 1]@.+ nodes :: LGraph d v e -> [Node] nodes gr = [0 .. nNodes gr - 1] {-# INLINE nodes #-} + -- | Return the number of edges in a graph. nEdges :: LGraph d v e -> Int- nEdges (LGraph g _) = igraphEcount g+ nEdges (LGraph g _) = unsafePerformIO $ igraphEcount g {-# INLINE nEdges #-} + -- | Return all edges. edges :: LGraph d v e -> [Edge] edges gr@(LGraph g _) = unsafePerformIO $ mapM (igraphEdge g) [0..n-1] where n = nEdges gr {-# INLINE edges #-} + -- | Whether a edge exists in the graph. hasEdge :: LGraph d v e -> Edge -> Bool- hasEdge (LGraph g _) (fr, to)- | igraphGetEid g fr to True False < 0 = False- | otherwise = True+ hasEdge (LGraph g _) (fr, to) = unsafePerformIO $ do+ i <- igraphGetEid g fr to True False+ return $ i >= 0 {-# INLINE hasEdge #-} - nodeLab :: Read v => LGraph d v e -> Node -> v- nodeLab (LGraph g _) i = read $ igraphCattributeVAS g vertexAttr i+ -- | Return the label of given node.+ nodeLab :: Serialize v => LGraph d v e -> Node -> v+ nodeLab (LGraph g _) i = unsafePerformIO $+ igraphHaskellAttributeVAS g vertexAttr i >>= fromBS {-# INLINE nodeLab #-} - nodeLabMaybe :: Read v => LGraph d v e -> Node -> Maybe v- nodeLabMaybe gr@(LGraph g _) i =- if igraphCattributeHasAttr g IgraphAttributeVertex vertexAttr- then Just $ nodeLab gr i- else Nothing- {-# INLINE nodeLabMaybe #-}-+ -- | Return all nodes that are associated with given label. getNodes :: (Hashable v, Eq v) => LGraph d v e -> v -> [Node] getNodes gr x = M.lookupDefault [] x $ _labelToNode gr {-# INLINE getNodes #-} - edgeLab :: Read e => LGraph d v e -> Edge -> e- edgeLab (LGraph g _) (fr,to) = read $ igraphCattributeEAS g edgeAttr $- igraphGetEid g fr to True True+ -- | Return the label of given edge.+ edgeLab :: Serialize e => LGraph d v e -> Edge -> e+ edgeLab (LGraph g _) (fr,to) = unsafePerformIO $+ igraphGetEid g fr to True True >>=+ igraphHaskellAttributeEAS g edgeAttr >>= fromBS {-# INLINE edgeLab #-} - edgeLabMaybe :: Read e => LGraph d v e -> Edge -> Maybe e- edgeLabMaybe gr@(LGraph g _) i =- if igraphCattributeHasAttr g IgraphAttributeEdge edgeAttr- then Just $ edgeLab gr i- else Nothing- {-# INLINE edgeLabMaybe #-}+ -- | Find the edge by edge ID.+ getEdgeByEid :: LGraph d v e -> Int -> Edge+ getEdgeByEid gr@(LGraph g _) i = unsafePerformIO $ igraphEdge g i+ {-# INLINE getEdgeByEid #-} - edgeLabByEid :: Read e => LGraph d v e -> Int -> e- edgeLabByEid (LGraph g _) i = read $ igraphCattributeEAS g edgeAttr i+ -- | Find the edge label by edge ID.+ edgeLabByEid :: Serialize e => LGraph d v e -> Int -> e+ edgeLabByEid (LGraph g _) i = unsafePerformIO $+ igraphHaskellAttributeEAS g edgeAttr i >>= fromBS {-# INLINE edgeLabByEid #-} - instance Graph U where isDirected = const False isD = const False@@ -136,17 +126,60 @@ isDirected = const True isD = const True -mkGraph :: (Graph d, Hashable v, Read v, Eq v, Show v, Show e)- => [v] -> [(Edge, e)] -> LGraph d v e+-- | Graph with labeled nodes and edges.+data LGraph d v e = LGraph+ { _graph :: IGraph+ , _labelToNode :: M.HashMap v [Node]+ }++instance (Graph d, Serialize v, Serialize e, Hashable v, Eq v)+ => Serialize (LGraph d v e) where+ put gr = do+ put $ nNodes gr+ go (nodeLab gr) (nNodes gr) 0+ put $ nEdges gr+ go (\i -> (getEdgeByEid gr i, edgeLabByEid gr i)) (nEdges gr) 0+ where+ go f n i | i >= n = return ()+ | otherwise = put (f i) >> go f n (i+1)+ get = do+ nn <- get+ nds <- replicateM nn get+ ne <- get+ es <- replicateM ne get+ return $ mkGraph nds es++-- | Decode a graph from a stream of inputs. This may be more memory efficient+-- than standard @decode@ function.+decodeC :: ( PrimMonad m, MonadThrow m, Graph d+ , Serialize v, Serialize e, Hashable v, Eq v )+ => ConduitT B.ByteString o m (LGraph d v e)+decodeC = do+ nn <- sinkGet get+ nds <- replicateM nn $ sinkGet get+ ne <- sinkGet get+ conduitGet2 get .| deserializeGraph nds ne++-- | Create a empty graph.+empty :: (Graph d, Hashable v, Serialize v, Eq v, Serialize e)+ => LGraph d v e+empty = runST $ new 0 >>= unsafeFreeze++-- | Create a graph.+mkGraph :: (Graph d, Hashable v, Serialize v, Eq v, Serialize e)+ => [v] -- ^ Nodes. Each will be assigned a ID from 0 to N.+ -> [LEdge e] -- ^ Labeled edges.+ -> LGraph d v e mkGraph vattr es = runST $ do g <- new 0- addLNodes n vattr g- addLEdges (map (\((fr,to),x) -> (fr,to,x)) es) g+ addLNodes vattr g+ addLEdges es g unsafeFreeze g where n = length vattr -fromLabeledEdges :: (Graph d, Hashable v, Read v, Eq v, Show v, Show e)+-- | Create a graph from labeled edges.+fromLabeledEdges :: (Graph d, Hashable v, Serialize v, Eq v, Serialize e) => [((v, v), e)] -> LGraph d v e fromLabeledEdges es = mkGraph labels es' where@@ -155,25 +188,76 @@ labels = S.toList $ S.fromList $ concat [ [a,b] | ((a,b),_) <- es ] labelToId = M.fromList $ zip labels [0..] -unsafeFreeze :: (Hashable v, Eq v, Read v, PrimMonad m) => MLGraph (PrimState m) d v e -> m (LGraph d v e)-unsafeFreeze (MLGraph g) = return $ LGraph g labToId+-- | Create a graph from a stream of labeled edges.+fromLabeledEdges' :: (PrimMonad m, Graph d, Hashable v, Serialize v, Eq v, Serialize e)+ => a -- ^ Input, usually a file+ -> (a -> ConduitT () ((v, v), e) m ()) -- ^ deserialize the input into a stream of edges+ -> m (LGraph d v e)+fromLabeledEdges' input mkConduit = do+ (labelToId, _, ne) <- runConduit $ mkConduit input .|+ foldlC f (M.empty, 0::Int, 0::Int)+ let getId x = M.lookupDefault undefined x labelToId+ runConduit $ mkConduit input .|+ mapC (\((v1, v2), e) -> ((getId v1, getId v2), e)) .|+ deserializeGraph (fst $ unzip $ sortBy (comparing snd) $ M.toList labelToId) ne where- labToId = M.fromListWith (++) $ zip labels $ map return [0..nV-1]- nV = igraphVcount g- labels = map (read . igraphCattributeVAS g vertexAttr) [0 .. nV-1]+ f (vs, nn, ne) ((v1, v2), _) =+ let (vs', nn') = add v1 $ add v2 (vs, nn)+ in (vs', nn', ne+1)+ where+ add v (m, i) = if v `M.member` m+ then (m, i)+ else (M.insert v i m, i + 1) -freeze :: (Hashable v, Eq v, Read v, PrimMonad m) => MLGraph (PrimState m) d v e -> m (LGraph d v e)+deserializeGraph :: ( PrimMonad m, Graph d, Hashable v, Serialize v+ , Eq v, Serialize e )+ => [v]+ -> Int -- ^ The number of edges+ -> ConduitT (LEdge e) o m (LGraph d v e)+deserializeGraph nds ne = do+ evec <- unsafePrimToPrim $ igraphVectorNew $ 2 * ne+ bsvec <- unsafePrimToPrim $ bsvectorNew ne+ let f i ((fr, to), attr) = unsafePrimToPrim $ do+ igraphVectorSet evec (i*2) $ fromIntegral fr+ igraphVectorSet evec (i*2+1) $ fromIntegral to+ asBS attr $ \bs -> with bs $ \ptr -> bsvectorSet bsvec i $ castPtr ptr+ return $ i + 1+ foldMC f 0+ gr@(MLGraph g) <- new 0+ addLNodes nds gr+ unsafePrimToPrim $ withEdgeAttr $ \eattr -> with (mkStrRec eattr bsvec) $ \ptr -> do+ vptr <- fromPtrs [castPtr ptr]+ withVectorPtr vptr (igraphAddEdges g evec . castPtr)+ unsafeFreeze gr+{-# INLINE deserializeGraph #-}++-- | Convert a mutable graph to immutable graph.+freeze :: (Hashable v, Eq v, Serialize v, PrimMonad m)+ => MLGraph (PrimState m) d v e -> m (LGraph d v e) freeze (MLGraph g) = do g' <- unsafePrimToPrim $ igraphCopy g unsafeFreeze (MLGraph g') -unsafeThaw :: PrimMonad m => LGraph d v e -> m (MLGraph (PrimState m) d v e)-unsafeThaw (LGraph g _) = return $ MLGraph g+-- | Convert a mutable graph to immutable graph. The original graph may not be+-- used afterwards.+unsafeFreeze :: (Hashable v, Eq v, Serialize v, PrimMonad m)+ => MLGraph (PrimState m) d v e -> m (LGraph d v e)+unsafeFreeze (MLGraph g) = unsafePrimToPrim $ do+ nV <- igraphVcount g+ labels <- forM [0 .. nV - 1] $ \i ->+ igraphHaskellAttributeVAS g vertexAttr i >>= fromBS+ return $ LGraph g $ M.fromListWith (++) $ zip labels $ map return [0..nV-1]+ where +-- | Create a mutable graph. thaw :: (PrimMonad m, Graph d) => LGraph d v e -> m (MLGraph (PrimState m) d v e) thaw (LGraph g _) = unsafePrimToPrim . liftM MLGraph . igraphCopy $ g --- | Find all neighbors of the given node+-- | Create a mutable graph. The original graph may not be used afterwards.+unsafeThaw :: PrimMonad m => LGraph d v e -> m (MLGraph (PrimState m) d v e)+unsafeThaw (LGraph g _) = return $ MLGraph g++-- | Find all neighbors of the given node. neighbors :: LGraph d v e -> Node -> [Node] neighbors gr i = unsafePerformIO $ do vs <- igraphVsAdj i IgraphAll@@ -195,7 +279,7 @@ vitToList vit -- | Keep nodes that satisfy the constraint-filterNodes :: (Hashable v, Eq v, Read v, Graph d)+filterNodes :: (Hashable v, Eq v, Serialize v, Graph d) => (LGraph d v e -> Node -> Bool) -> LGraph d v e -> LGraph d v e filterNodes f gr = runST $ do let deleted = filter (not . f gr) $ nodes gr@@ -204,7 +288,7 @@ unsafeFreeze gr' -- | Apply a function to change nodes' labels.-mapNodes :: (Graph d, Read v1, Show v2, Hashable v2, Eq v2, Read v2)+mapNodes :: (Graph d, Serialize v1, Serialize v2, Hashable v2, Eq v2) => (Node -> v1 -> v2) -> LGraph d v1 e -> LGraph d v2 e mapNodes f gr = runST $ do (MLGraph gptr) <- thaw gr@@ -213,7 +297,7 @@ unsafeFreeze gr' -- | Apply a function to change edges' labels.-mapEdges :: (Graph d, Read e1, Show e2, Hashable v, Eq v, Read v)+mapEdges :: (Graph d, Serialize e1, Serialize e2, Hashable v, Eq v, Serialize v) => (Edge -> e1 -> e2) -> LGraph d v e1 -> LGraph d v e2 mapEdges f gr = runST $ do (MLGraph gptr) <- thaw gr@@ -223,9 +307,8 @@ setEdgeAttr x (f e $ edgeLabByEid gr x) gr' unsafeFreeze gr' ---- | Keep nodes that satisfy the constraint-filterEdges :: (Hashable v, Eq v, Read v, Graph d)+-- | Keep nodes that satisfy the constraint.+filterEdges :: (Hashable v, Eq v, Serialize v, Graph d) => (LGraph d v e -> Edge -> Bool) -> LGraph d v e -> LGraph d v e filterEdges f gr = runST $ do let deleted = filter (not . f gr) $ edges gr@@ -233,23 +316,25 @@ delEdges deleted gr' unsafeFreeze gr' --- | Map a function over the node labels in a graph-nmap :: (Graph d, Read v, Hashable u, Read u, Eq u, Show u)+-- | Map a function over the node labels in a graph.+nmap :: (Graph d, Serialize v, Hashable u, Serialize u, Eq u) => ((Node, v) -> u) -> LGraph d v e -> LGraph d u e nmap fn gr = unsafePerformIO $ do (MLGraph g) <- thaw gr forM_ (nodes gr) $ \i -> do let label = fn (i, nodeLab gr i)- igraphCattributeVASSet g vertexAttr i (show label)+ asBS label $ \bs ->+ with bs (igraphHaskellAttributeVASSet g vertexAttr i) unsafeFreeze (MLGraph g) --- | Map a function over the edge labels in a graph-emap :: (Graph d, Read v, Hashable v, Eq v, Read e1, Show e2)+-- | Map a function over the edge labels in a graph.+emap :: (Graph d, Serialize v, Hashable v, Eq v, Serialize e1, Serialize e2) => ((Edge, e1) -> e2) -> LGraph d v e1 -> LGraph d v e2 emap fn gr = unsafePerformIO $ do (MLGraph g) <- thaw gr forM_ (edges gr) $ \(fr, to) -> do+ i <- igraphGetEid g fr to True True let label = fn ((fr,to), edgeLabByEid gr i)- i = igraphGetEid g fr to True True- igraphCattributeEASSet g edgeAttr i (show label)+ asBS label $ \bs ->+ with bs (igraphHaskellAttributeEASSet g edgeAttr i) unsafeFreeze (MLGraph g)
src/IGraph/Clique.hs view
@@ -17,7 +17,7 @@ cliques gr (lo, hi) = unsafePerformIO $ do vpptr <- igraphVectorPtrNew 0 _ <- igraphCliques (_graph gr) vpptr lo hi- (map.map) truncate <$> vectorPPtrToList vpptr+ (map.map) truncate <$> toLists vpptr maximalCliques :: LGraph d v e -> (Int, Int) -- ^ Minimum and maximum size of the cliques to be returned.@@ -26,4 +26,4 @@ maximalCliques gr (lo, hi) = unsafePerformIO $ do vpptr <- igraphVectorPtrNew 0 _ <- igraphMaximalCliques (_graph gr) vpptr lo hi- (map.map) truncate <$> vectorPPtrToList vpptr+ (map.map) truncate <$> toLists vpptr
src/IGraph/Community.hs view
@@ -4,32 +4,31 @@ , findCommunity ) where -import Control.Monad-import Control.Applicative ((<$>))-import Foreign-import Foreign.C.Types-import System.IO.Unsafe (unsafePerformIO)-import Data.List-import Data.Ord-import Data.Function (on)-import Data.Default.Class+import Control.Applicative ((<$>))+import Control.Monad+import Data.Default.Class+import Data.Function (on)+import Data.List+import Data.Ord+import Foreign+import Foreign.C.Types+import System.IO.Unsafe (unsafePerformIO) -import IGraph-import IGraph.Mutable (U)-import IGraph.Internal.Data-import IGraph.Internal.Constants-import IGraph.Internal.Community-import IGraph.Internal.Arpack+import IGraph+import IGraph.Internal.Arpack+import IGraph.Internal.Community+import IGraph.Internal.Constants+import IGraph.Internal.Data data CommunityOpt = CommunityOpt- { _method :: CommunityMethod- , _weights :: Maybe [Double]- , _nIter :: Int -- ^ [LeadingEigenvector] number of iterations, default is 10000- , _nSpins :: Int -- ^ [Spinglass] number of spins, default is 25+ { _method :: CommunityMethod+ , _weights :: Maybe [Double]+ , _nIter :: Int -- ^ [LeadingEigenvector] number of iterations, default is 10000+ , _nSpins :: Int -- ^ [Spinglass] number of spins, default is 25 , _startTemp :: Double -- ^ [Spinglass] the temperature at the start- , _stopTemp :: Double -- ^ [Spinglass] the algorithm stops at this temperature- , _coolFact :: Double -- ^ [Spinglass] the cooling factor for the simulated annealing- , _gamma :: Double -- ^ [Spinglass] the gamma parameter of the algorithm. + , _stopTemp :: Double -- ^ [Spinglass] the algorithm stops at this temperature+ , _coolFact :: Double -- ^ [Spinglass] the cooling factor for the simulated annealing+ , _gamma :: Double -- ^ [Spinglass] the gamma parameter of the algorithm. } data CommunityMethod = LeadingEigenvector@@ -51,8 +50,8 @@ findCommunity gr opt = unsafePerformIO $ do result <- igraphVectorNew 0 ws <- case _weights opt of- Just w -> listToVector w- _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr+ Just w -> fromList w+ _ -> liftM Vector $ newForeignPtr_ $ castPtr nullPtr case _method opt of LeadingEigenvector -> do@@ -60,7 +59,7 @@ igraphCommunityLeadingEigenvector (_graph gr) ws nullPtr result (_nIter opt) ap nullPtr False nullPtr nullPtr nullPtr- nullFunPtr nullPtr + nullFunPtr nullPtr Spinglass -> igraphCommunitySpinglass (_graph gr) ws nullPtr nullPtr result nullPtr (_nSpins opt) False (_startTemp opt)@@ -69,5 +68,4 @@ IgraphSpincommImpOrig 1.0 liftM ( map (fst . unzip) . groupBy ((==) `on` snd)- . sortBy (comparing snd) . zip [0..] ) $ vectorPtrToList result-+ . sortBy (comparing snd) . zip [0..] ) $ toList result
src/IGraph/Exporter/GEXF.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-} module IGraph.Exporter.GEXF ( NodeAttr(..) , defaultNodeAttributes@@ -7,23 +9,35 @@ , writeGEXF ) where -import Data.Hashable-import Data.Colour (AlphaColour, black, over, alphaChannel, opaque)-import Data.Colour.SRGB (toSRGB24, channelRed, channelBlue, channelGreen)-import Text.XML.HXT.Core-import Data.Tree.NTree.TypeDefs-import Text.XML.HXT.DOM.TypeDefs-import IGraph+import Data.Colour (AlphaColour, alphaChannel, black,+ opaque, over)+import Data.Colour.SRGB (channelBlue, channelGreen,+ channelRed, toSRGB24)+import Data.Hashable+import Data.Serialize+import Data.Tree.NTree.TypeDefs+import GHC.Generics+import IGraph+import Text.XML.HXT.Core+import Text.XML.HXT.DOM.TypeDefs +instance Serialize (AlphaColour Double) where+ get = do+ x <- get+ return $ read x+ put x = put $ show x+ data NodeAttr = NodeAttr- { _size :: Double+ { _size :: Double , _nodeColour :: AlphaColour Double- , _nodeLabel :: String- , _positionX :: Double- , _positionY :: Double+ , _nodeLabel :: String+ , _positionX :: Double+ , _positionY :: Double , _nodeZindex :: Int- } deriving (Show, Read, Eq)+ } deriving (Show, Read, Eq, Generic) +instance Serialize NodeAttr+ instance Hashable NodeAttr where hashWithSalt salt at = hashWithSalt salt $ _nodeLabel at @@ -38,12 +52,14 @@ } data EdgeAttr = EdgeAttr- { _edgeLabel :: String- , _edgeColour :: AlphaColour Double- , _edgeWeight :: Double+ { _edgeLabel :: String+ , _edgeColour :: AlphaColour Double+ , _edgeWeight :: Double , _edgeArrowLength :: Double- , _edgeZindex :: Int- } deriving (Show, Read, Eq)+ , _edgeZindex :: Int+ } deriving (Show, Read, Eq, Generic)++instance Serialize EdgeAttr instance Hashable EdgeAttr where hashWithSalt salt at = hashWithSalt salt $ _edgeLabel at
src/IGraph/Exporter/Graphics.hs view
@@ -29,7 +29,7 @@ drawEdge (from, to) = ( arrowBetween' ( with & arrowTail .~ noTail & arrowHead .~ arrowH- & headStyle %~ fc red+ & headStyle %~ fcA (_edgeColour eattr) & headLength .~ output (_edgeArrowLength eattr) ) start end # lwO (_edgeWeight eattr) # lcA (_edgeColour eattr), _edgeZindex eattr ) where
src/IGraph/Generators.hs view
@@ -1,14 +1,21 @@ module IGraph.Generators ( ErdosRenyiModel(..) , erdosRenyiGame+ , degreeSequenceGame+ , rewire ) where -import IGraph-import IGraph.Mutable-import IGraph.Internal.Graph-import IGraph.Internal.Constants-import IGraph.Internal.Initialization+import Control.Monad (when)+import Data.Hashable (Hashable)+import Data.Serialize (Serialize) +import IGraph+import IGraph.Internal.Constants+import IGraph.Internal.Data+import IGraph.Internal.Graph+import IGraph.Internal.Initialization+import IGraph.Mutable+ data ErdosRenyiModel = GNP Int Double | GNM Int Int @@ -24,3 +31,24 @@ gp <- igraphInit >> igraphErdosRenyiGame IgraphErdosRenyiGnm n (fromIntegral m) (isD d) self unsafeFreeze $ MLGraph gp++-- | Generates a random graph with a given degree sequence.+degreeSequenceGame :: [Int] -- ^ Out degree+ -> [Int] -- ^ In degree+ -> IO (LGraph D () ())+degreeSequenceGame out_deg in_deg = do+ out_deg' <- fromList $ map fromIntegral out_deg+ in_deg' <- fromList $ map fromIntegral in_deg+ gp <- igraphDegreeSequenceGame out_deg' in_deg' IgraphDegseqSimple+ unsafeFreeze $ MLGraph gp++-- | Randomly rewires a graph while preserving the degree distribution.+rewire :: (Graph d, Hashable v, Serialize v, Eq v, Serialize e)+ => Int -- ^ Number of rewiring trials to perform.+ -> LGraph d v e+ -> IO (LGraph d v e)+rewire n gr = do+ (MLGraph gptr) <- thaw gr+ err <- igraphRewire gptr n IgraphRewiringSimple+ when (err /= 0) $ error "failed to rewire graph!"+ unsafeFreeze $ MLGraph gptr
src/IGraph/Internal/Arpack.chs view
@@ -5,8 +5,9 @@ import Foreign import Foreign.C.Types -#include "haskelligraph.h"+#include "haskell_igraph.h" -{#pointer *igraph_arpack_options_t as ArpackOptPtr foreign finalizer igraph_arpack_destroy newtype#}+{#pointer *igraph_arpack_options_t as ArpackOpt foreign newtype#} -{#fun igraph_arpack_new as ^ { } -> `ArpackOptPtr' #}+{#fun igraph_arpack_options_init as igraphArpackNew+ { + } -> `ArpackOpt' #}
src/IGraph/Internal/Attribute.chs view
@@ -1,9 +1,11 @@ {-# LANGUAGE ForeignFunctionInterface #-} module IGraph.Internal.Attribute where -import qualified Data.ByteString.Char8 as B+import Data.ByteString (packCStringLen)+import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Control.Monad import Control.Applicative+import Data.Serialize (Serialize, decode, encode) import Foreign import Foreign.C.Types import Foreign.C.String@@ -14,18 +16,39 @@ {#import IGraph.Internal.Constants #} #include "igraph/igraph.h"+#include "haskell_attributes.h" -makeAttributeRecord :: Show a- => String -- ^ name of the attribute- -> [a] -- ^ values of the attribute- -> AttributeRecord-makeAttributeRecord name xs = unsafePerformIO $ do- ptr <- newCAString name- value <- listToStrVector $ map (B.pack . show) xs- return $ AttributeRecord ptr 2 value+-- The returned object will not be trackced by Haskell's GC. It should be freed+-- by foreign codes.+asBS :: Serialize a => a -> (BSLen -> IO b) -> IO b+asBS x fn = unsafeUseAsCStringLen (encode x) (fn . BSLen)+{-# INLINE asBS #-} -data AttributeRecord = AttributeRecord CString Int StrVectorPtr+asBSVector :: Serialize a => [a] -> (BSVector -> IO b) -> IO b+asBSVector values fn = loop [] values+ where+ loop acc (x:xs) = unsafeUseAsCStringLen (encode x) $ \ptr ->+ loop (BSLen ptr : acc) xs+ loop acc _ = toBSVector (reverse acc) >>= fn+{-# INLINE asBSVector #-} +fromBS :: Serialize a => Ptr BSLen -> IO a+fromBS ptr = do+ BSLen x <- peek ptr+ result <- decode <$> packCStringLen x+ case result of+ Left msg -> error msg+ Right r -> return r+{-# INLINE fromBS #-}++mkStrRec :: CString -- ^ name of the attribute+ -> BSVector -- ^ values of the attribute+ -> AttributeRecord+mkStrRec name xs = AttributeRecord name 2 xs+{-# INLINE mkStrRec #-}++data AttributeRecord = AttributeRecord CString Int BSVector+ instance Storable AttributeRecord where sizeOf _ = {#sizeof igraph_attribute_record_t #} alignment _ = {#alignof igraph_attribute_record_t #}@@ -34,27 +57,27 @@ <*> liftM fromIntegral ({#get igraph_attribute_record_t->type #} p) <*> ( do ptr <- {#get igraph_attribute_record_t->value #} p fptr <- newForeignPtr_ . castPtr $ ptr- return $ StrVectorPtr fptr )+ return $ BSVector fptr ) poke p (AttributeRecord name t vptr) = do {#set igraph_attribute_record_t.name #} p name {#set igraph_attribute_record_t.type #} p $ fromIntegral t- withStrVectorPtr vptr $ \ptr ->+ withBSVector vptr $ \ptr -> {#set igraph_attribute_record_t.value #} p $ castPtr ptr -{#fun pure igraph_cattribute_has_attr as ^ { `IGraphPtr', `AttributeElemtype', `String' } -> `Bool' #}+{#fun igraph_haskell_attribute_has_attr as ^ { `IGraph', `AttributeElemtype', `String' } -> `Bool' #} -{#fun igraph_cattribute_GAN_set as ^ { `IGraphPtr', `String', `Double' } -> `Int' #}+{#fun igraph_haskell_attribute_GAN_set as ^ { `IGraph', `String', `Double' } -> `Int' #} -{#fun pure igraph_cattribute_GAN as ^ { `IGraphPtr', `String' } -> `Double' #}+{#fun igraph_haskell_attribute_GAN as ^ { `IGraph', `String' } -> `Double' #} -{#fun pure igraph_cattribute_VAS as ^ { `IGraphPtr', `String', `Int' } -> `String' #}+{#fun igraph_haskell_attribute_VAS as ^ { `IGraph', `String', `Int' } -> `Ptr BSLen' castPtr #} -{#fun pure igraph_cattribute_EAN as ^ { `IGraphPtr', `String', `Int' } -> `Double' #}+{#fun igraph_haskell_attribute_EAN as ^ { `IGraph', `String', `Int' } -> `Double' #} -{#fun pure igraph_cattribute_EAS as ^ { `IGraphPtr', `String', `Int' } -> `String' #}+{#fun igraph_haskell_attribute_EAS as ^ { `IGraph', `String', `Int' } -> `Ptr BSLen' castPtr #} -{#fun igraph_cattribute_EAS_setv as ^ { `IGraphPtr', `String', `StrVectorPtr' } -> `Int' #}+{#fun igraph_haskell_attribute_EAS_setv as ^ { `IGraph', `String', `BSVector' } -> `Int' #} -{#fun igraph_cattribute_VAS_set as ^ { `IGraphPtr', `String', `Int', `String' } -> `Int' #}+{#fun igraph_haskell_attribute_VAS_set as ^ { `IGraph', `String', `Int', castPtr `Ptr BSLen' } -> `Int' #} -{#fun igraph_cattribute_EAS_set as ^ { `IGraphPtr', `String', `Int', `String' } -> `Int' #}+{#fun igraph_haskell_attribute_EAS_set as ^ { `IGraph', `String', `Int', castPtr `Ptr BSLen' } -> `Int' #}
+ src/IGraph/Internal/C2HS.hs view
@@ -0,0 +1,73 @@+module IGraph.Internal.C2HS (++ -- * Conversion between C and Haskell types+ cIntConv, cFloatConv, cToBool, cFromBool, cToEnum, cFromEnum,++ -- * Composite marshalling functions+ peekIntConv, peekFloatConv,++) where++-- system+import Control.Monad+import Foreign+import Foreign.C+++-- Conversions -----------------------------------------------------------------+--++-- | Integral conversion+--+{-# INLINE cIntConv #-}+cIntConv :: (Integral a, Integral b) => a -> b+cIntConv = fromIntegral++-- | Floating conversion+--+{-# INLINE [1] cFloatConv #-}+cFloatConv :: (RealFloat a, RealFloat b) => a -> b+cFloatConv = realToFrac+-- As this conversion by default goes via `Rational', it can be very slow...+{-# RULES+ "cFloatConv/Float->Float" forall (x::Float). cFloatConv x = x;+ "cFloatConv/Double->Double" forall (x::Double). cFloatConv x = x;+ "cFloatConv/Float->CFloat" forall (x::Float). cFloatConv x = CFloat x;+ "cFloatConv/CFloat->Float" forall (x::Float). cFloatConv CFloat x = x;+ "cFloatConv/Double->CDouble" forall (x::Double). cFloatConv x = CDouble x;+ "cFloatConv/CDouble->Double" forall (x::Double). cFloatConv CDouble x = x+ #-}++-- | Obtain C value from Haskell 'Bool'.+--+{-# INLINE cFromBool #-}+cFromBool :: Num a => Bool -> a+cFromBool = fromBool++-- | Obtain Haskell 'Bool' from C value.+--+{-# INLINE cToBool #-}+cToBool :: (Eq a, Num a) => a -> Bool+cToBool = toBool++-- | Convert a C enumeration to Haskell.+--+{-# INLINE cToEnum #-}+cToEnum :: (Integral i, Enum e) => i -> e+cToEnum = toEnum . cIntConv++-- | Convert a Haskell enumeration to C.+--+{-# INLINE cFromEnum #-}+cFromEnum :: (Enum e, Integral i) => e -> i+cFromEnum = cIntConv . fromEnum++-- | Marshalling of numerals+--+{-# INLINE peekIntConv #-}+peekIntConv :: (Storable a, Integral a, Integral b) => Ptr a -> IO b+peekIntConv = liftM cIntConv . peek++{-# INLINE peekFloatConv #-}+peekFloatConv :: (Storable a, RealFloat a, RealFloat b) => Ptr a -> IO b+peekFloatConv = liftM cFloatConv . peek
src/IGraph/Internal/Clique.chs view
@@ -10,8 +10,8 @@ {#import IGraph.Internal.Graph #} {#import IGraph.Internal.Data #} -#include "igraph/igraph.h"+#include "haskell_igraph.h" -{#fun igraph_cliques as ^ { `IGraphPtr', `VectorPPtr', `Int', `Int' } -> `Int' #}+{#fun igraph_cliques as ^ { `IGraph', `VectorPtr', `Int', `Int' } -> `Int' #} -{#fun igraph_maximal_cliques as ^ { `IGraphPtr', `VectorPPtr', `Int', `Int' } -> `Int' #}+{#fun igraph_maximal_cliques as ^ { `IGraph', `VectorPtr', `Int', `Int' } -> `Int' #}
src/IGraph/Internal/Community.chs view
@@ -9,15 +9,15 @@ {#import IGraph.Internal.Data #} {#import IGraph.Internal.Constants #} -#include "igraph/igraph.h"+#include "haskell_igraph.h" {#fun igraph_community_spinglass as ^-{ `IGraphPtr'-, `VectorPtr'+{ `IGraph'+, `Vector' , id `Ptr CDouble' , id `Ptr CDouble'-, `VectorPtr'-, id `Ptr VectorPtr'+, `Vector'+, id `Ptr Vector' , `Int' , `Bool' , `Double'@@ -30,25 +30,25 @@ } -> `Int' #} {#fun igraph_community_leading_eigenvector as ^-{ `IGraphPtr'-, `VectorPtr'-, id `Ptr MatrixPtr'-, `VectorPtr'+{ `IGraph'+, `Vector'+, id `Ptr Matrix'+, `Vector' , `Int'-, `ArpackOptPtr'+, `ArpackOpt' , id `Ptr CDouble' , `Bool'-, id `Ptr VectorPtr'-, id `Ptr VectorPPtr'+, id `Ptr Vector' , id `Ptr VectorPtr'+, id `Ptr Vector' , id `T' , id `Ptr ()' } -> `Int' #} -type T = FunPtr ( Ptr VectorPtr+type T = FunPtr ( Ptr Vector -> CLong -> CDouble- -> Ptr VectorPtr+ -> Ptr Vector -> FunPtr (Ptr CDouble -> Ptr CDouble -> CInt -> Ptr () -> IO CInt) -> Ptr () -> Ptr ()
src/IGraph/Internal/Constants.chs view
@@ -28,3 +28,9 @@ {#enum igraph_erdos_renyi_t as ErdosRenyi {underscoreToCase} deriving (Show, Read, Eq) #}++{#enum igraph_rewiring_t as Rewiring {underscoreToCase}+ deriving (Show, Read, Eq) #}++{#enum igraph_degseq_t as Degseq {underscoreToCase}+ deriving (Show, Read, Eq) #}
src/IGraph/Internal/Data.chs view
@@ -1,6 +1,52 @@ {-# LANGUAGE ForeignFunctionInterface #-}-module IGraph.Internal.Data where+module IGraph.Internal.Data+ ( Vector(..)+ , withVector+ , igraphVectorNew+ , fromList+ , toList+ , igraphVectorNull+ , igraphVectorFill+ , igraphVectorE+ , igraphVectorSet+ , igraphVectorTail+ , igraphVectorSize+ , igraphVectorCopyTo + , VectorPtr(..)+ , withVectorPtr+ , igraphVectorPtrNew+ , fromPtrs+ , toLists++ , StrVector(..)+ , withStrVector+ , igraphStrvectorNew+ , igraphStrvectorGet+ , toStrVector++ , BSLen(..)+ , BSVector(..)+ , withBSVector+ , bsvectorNew+ , bsvectorSet+ , toBSVector++ , Matrix(..)+ , withMatrix+ , igraphMatrixNew+ , igraphMatrixNull+ , igraphMatrixFill+ , igraphMatrixE+ , igraphMatrixSet+ , igraphMatrixCopyTo+ , igraphMatrixNrow+ , igraphMatrixNcol+ , fromRowLists+ , toRowLists+ , toColumnLists+ ) where+ import Control.Monad import qualified Data.ByteString.Char8 as B import Foreign@@ -10,94 +56,109 @@ import Data.List (transpose) import Data.List.Split (chunksOf) -#include "haskelligraph.h"+#include "haskell_igraph.h"+#include "bytestring.h" -{#pointer *igraph_vector_t as VectorPtr foreign finalizer igraph_vector_destroy newtype#}+--------------------------------------------------------------------------------+-- Igraph vector+-------------------------------------------------------------------------------- +{#pointer *igraph_vector_t as Vector foreign finalizer+ igraph_vector_destroy newtype#}+ -- Construtors and destructors -{#fun igraph_vector_init as igraphVectorNew { +, `Int' } -> `VectorPtr' #}+{#fun igraph_vector_init as igraphVectorNew { +, `Int' } -> `Vector' #} -listToVector :: [Double] -> IO VectorPtr-listToVector xs = do- vec <- igraphVectorNew n- forM_ (zip [0..] xs) $ \(i,x) -> igraphVectorSet vec i x- return vec- where- n = length xs+{#fun igraph_vector_init_copy as ^ { +, id `Ptr CDouble', `Int' } -> `Vector' #} -vectorPtrToList :: VectorPtr -> IO [Double]-vectorPtrToList vptr = do- n <- igraphVectorSize vptr+fromList :: [Double] -> IO Vector+fromList xs = withArrayLen (map realToFrac xs) $ \n ptr ->+ igraphVectorInitCopy ptr n+{-# INLINE fromList #-}++toList :: Vector -> IO [Double]+toList vec = do+ n <- igraphVectorSize vec allocaArray n $ \ptr -> do- igraphVectorCopyTo vptr ptr+ igraphVectorCopyTo vec ptr liftM (map realToFrac) $ peekArray n ptr+{-# INLINE toList #-} -- Initializing elements -{#fun igraph_vector_null as ^ { `VectorPtr' } -> `()' #}+{#fun igraph_vector_null as ^ { `Vector' } -> `()' #} -{#fun igraph_vector_fill as ^ { `VectorPtr', `Double' } -> `()' #}+{#fun igraph_vector_fill as ^ { `Vector', `Double' } -> `()' #} -- Accessing elements -{#fun pure igraph_vector_e as ^ { `VectorPtr', `Int' } -> `Double' #}+{#fun pure igraph_vector_e as ^ { `Vector', `Int' } -> `Double' #} -{#fun igraph_vector_set as ^ { `VectorPtr', `Int', `Double' } -> `()' #}+{#fun igraph_vector_set as ^ { `Vector', `Int', `Double' } -> `()' #} -{#fun pure igraph_vector_tail as ^ { `VectorPtr' } -> `Double' #}+{#fun pure igraph_vector_tail as ^ { `Vector' } -> `Double' #} -- Copying vectors -{#fun igraph_vector_copy_to as ^ { `VectorPtr', id `Ptr CDouble' } -> `()' #}+{#fun igraph_vector_copy_to as ^ { `Vector', id `Ptr CDouble' } -> `()' #} -- Vector properties-{#fun igraph_vector_size as ^ { `VectorPtr' } -> `Int' #}+{#fun igraph_vector_size as ^ { `Vector' } -> `Int' #} -{#pointer *igraph_vector_ptr_t as VectorPPtr foreign finalizer igraph_vector_ptr_destroy_all newtype#}+{#pointer *igraph_vector_ptr_t as VectorPtr foreign finalizer+ igraph_vector_ptr_destroy_all newtype#} -{#fun igraph_vector_ptr_init as igraphVectorPtrNew { +, `Int' } -> `VectorPPtr' #}+{#fun igraph_vector_ptr_init as igraphVectorPtrNew { +, `Int' } -> `VectorPtr' #} -{#fun igraph_vector_ptr_e as ^ { `VectorPPtr', `Int' } -> `Ptr ()' #}-{#fun igraph_vector_ptr_set as ^ { `VectorPPtr', `Int', id `Ptr ()' } -> `()' #}-{#fun igraph_vector_ptr_size as ^ { `VectorPPtr' } -> `Int' #}+{#fun igraph_vector_ptr_e as ^ { `VectorPtr', `Int' } -> `Ptr ()' #}+{#fun igraph_vector_ptr_set as ^ { `VectorPtr', `Int', id `Ptr ()' } -> `()' #}+{#fun igraph_vector_ptr_size as ^ { `VectorPtr' } -> `Int' #} -listToVectorP :: [Ptr ()] -> IO VectorPPtr-listToVectorP xs = do+fromPtrs :: [Ptr ()] -> IO VectorPtr+fromPtrs xs = do vptr <- igraphVectorPtrNew n forM_ (zip [0..] xs) $ \(i,x) -> igraphVectorPtrSet vptr i x return vptr where n = length xs+{-# INLINE fromPtrs #-} -vectorPPtrToList :: VectorPPtr -> IO [[Double]]-vectorPPtrToList vpptr = do+toLists :: VectorPtr -> IO [[Double]]+toLists vpptr = do n <- igraphVectorPtrSize vpptr forM [0..n-1] $ \i -> do vptr <- igraphVectorPtrE vpptr i- fptr <- newForeignPtr_ $ castPtr vptr- vectorPtrToList $ VectorPtr fptr+ vec <- newForeignPtr_ $ castPtr vptr+ toList $ Vector vec+{-# INLINE toLists #-} +--------------------------------------------------------------------------------+-- Igraph string vector+-------------------------------------------------------------------------------- -{#pointer *igraph_strvector_t as StrVectorPtr foreign finalizer igraph_strvector_destroy newtype#}+{#pointer *igraph_strvector_t as StrVector foreign finalizer igraph_strvector_destroy newtype#} -{#fun igraph_strvector_init as igraphStrvectorNew { +, `Int' } -> `StrVectorPtr' #}+{#fun igraph_strvector_init as igraphStrvectorNew { +, `Int' } -> `StrVector' #} -{#fun igraph_strvector_get_ as igraphStrvectorGet' { `StrVectorPtr', `Int' } -> `Ptr CString' id #}+{#fun igraph_strvector_get as ^+ { `StrVector'+ , `Int'+ , alloca- `String' peekString*+ } -> `CInt' void-#} -igraphStrvectorGet :: StrVectorPtr -> Int -> String-igraphStrvectorGet vec i = unsafePerformIO $ do- ptr <- igraphStrvectorGet' vec i- peek ptr >>= peekCString+peekString :: Ptr CString -> IO String+peekString ptr = peek ptr >>= peekCString+{-# INLINE peekString #-} -{#fun igraph_strvector_set as ^ { `StrVectorPtr', `Int', id `CString'} -> `()' #}-{#fun igraph_strvector_set2 as ^ { `StrVectorPtr', `Int', id `CString', `Int'} -> `()' #}+{#fun igraph_strvector_set as ^ { `StrVector', `Int', id `CString'} -> `()' #}+{#fun igraph_strvector_set2 as ^ { `StrVector', `Int', id `CString', `Int'} -> `()' #} -listToStrVector :: [B.ByteString] -> IO StrVectorPtr-listToStrVector xs = do+toStrVector :: [B.ByteString] -> IO StrVector+toStrVector xs = do vec <- igraphStrvectorNew n forM_ (zip [0..] xs) $ \(i,x) -> B.useAsCString x (igraphStrvectorSet vec i) return vec@@ -105,42 +166,84 @@ n = length xs -{#pointer *igraph_matrix_t as MatrixPtr foreign finalizer igraph_matrix_destroy newtype#}+--------------------------------------------------------------------------------+-- Customized string vector+-------------------------------------------------------------------------------- -{#fun igraph_matrix_init as igraphMatrixNew { +, `Int', `Int' } -> `MatrixPtr' #}+newtype BSLen = BSLen CStringLen -{#fun igraph_matrix_null as ^ { `MatrixPtr' } -> `()' #}+instance Storable BSLen where+ sizeOf _ = {#sizeof bytestring_t #}+ alignment _ = {#alignof bytestring_t #}+ peek p = do+ n <- ({#get bytestring_t->len #} p)+ ptr <- {#get bytestring_t->value #} p+ return $ BSLen (ptr, fromIntegral n)+ poke p (BSLen (ptr, n)) = {#set bytestring_t.len #} p (fromIntegral n) >>+ {#set bytestring_t.value #} p ptr -{#fun igraph_matrix_fill as ^ { `MatrixPtr', `Double' } -> `()' #}+{#pointer *bsvector_t as BSVector foreign finalizer bsvector_destroy newtype#} -{#fun igraph_matrix_e as ^ { `MatrixPtr', `Int', `Int' } -> `Double' #}+{#fun bsvector_init as bsvectorNew { +, `Int' } -> `BSVector' #} -{#fun igraph_matrix_set as ^ { `MatrixPtr', `Int', `Int', `Double' } -> `()' #}+--{#fun bsvector_get as bsVectorGet { `BSVectorPtr', `Int', + } -> `Ptr (Ptr BSLen)' id #} -{#fun igraph_matrix_copy_to as ^ { `MatrixPtr', id `Ptr CDouble' } -> `()' #}+{-+bsVectorGet :: BSVectorPtr -> Int -> BSLen+bsVectorGet vec i = unsafePerformIO $ do+ ptrptr <- bsVectorGet vec i+ peek ptrptr >>= peek+ -} -{#fun igraph_matrix_nrow as ^ { `MatrixPtr' } -> `Int' #}+{#fun bsvector_set as ^ { `BSVector', `Int', `Ptr ()'} -> `()' #} -{#fun igraph_matrix_ncol as ^ { `MatrixPtr' } -> `Int' #}+toBSVector :: [BSLen] -> IO BSVector+toBSVector xs = do+ vec <- bsvectorNew n+ forM_ (zip [0..] xs) $ \(i, x) -> with x $ \ptr -> bsvectorSet vec i $ castPtr ptr+ return vec+ where+ n = length xs ++{#pointer *igraph_matrix_t as Matrix foreign finalizer igraph_matrix_destroy newtype#}++{#fun igraph_matrix_init as igraphMatrixNew { +, `Int', `Int' } -> `Matrix' #}++{#fun igraph_matrix_null as ^ { `Matrix' } -> `()' #}++{#fun igraph_matrix_fill as ^ { `Matrix', `Double' } -> `()' #}++{#fun igraph_matrix_e as ^ { `Matrix', `Int', `Int' } -> `Double' #}++{#fun igraph_matrix_set as ^ { `Matrix', `Int', `Int', `Double' } -> `()' #}++{#fun igraph_matrix_copy_to as ^ { `Matrix', id `Ptr CDouble' } -> `()' #}++{#fun igraph_matrix_nrow as ^ { `Matrix' } -> `Int' #}++{#fun igraph_matrix_ncol as ^ { `Matrix' } -> `Int' #}+ -- row lists to matrix-listsToMatrixPtr :: [[Double]] -> IO MatrixPtr-listsToMatrixPtr xs = do- mptr <- igraphMatrixNew r c- forM_ (zip [0..] xs) $ \(i, row) ->- forM_ (zip [0..] row) $ \(j,v) ->- igraphMatrixSet mptr i j v- return mptr+fromRowLists :: [[Double]] -> IO Matrix+fromRowLists xs+ | all (==c) $ map length xs = do+ mptr <- igraphMatrixNew r c+ forM_ (zip [0..] xs) $ \(i, row) ->+ forM_ (zip [0..] row) $ \(j,v) ->+ igraphMatrixSet mptr i j v+ return mptr+ | otherwise = error "Not a matrix." where r = length xs- c = maximum $ map length xs+ c = length $ head xs -- to row lists-matrixPtrToLists :: MatrixPtr -> IO [[Double]]-matrixPtrToLists = liftM transpose . matrixPtrToColumnLists+toRowLists :: Matrix -> IO [[Double]]+toRowLists = liftM transpose . toColumnLists -matrixPtrToColumnLists :: MatrixPtr -> IO [[Double]]-matrixPtrToColumnLists mptr = do+toColumnLists :: Matrix -> IO [[Double]]+toColumnLists mptr = do r <- igraphMatrixNrow mptr c <- igraphMatrixNcol mptr xs <- allocaArray (r*c) $ \ptr -> do
src/IGraph/Internal/Graph.chs view
@@ -6,54 +6,80 @@ import Foreign.C.Types import System.IO.Unsafe (unsafePerformIO) +import IGraph.Internal.C2HS {#import IGraph.Internal.Initialization #} {#import IGraph.Internal.Data #} {#import IGraph.Internal.Constants #} -#include "haskelligraph.h"+#include "haskell_igraph.h" -{#pointer *igraph_t as IGraphPtr foreign finalizer igraph_destroy newtype#}+--------------------------------------------------------------------------------+-- Graph Constructors and Destructors+-------------------------------------------------------------------------------- --- | create a igraph object and attach a finalizer-igraphNew :: Int -> Bool -> HasInit -> IO IGraphPtr-igraphNew n directed _ = igraphNew' n directed+{#pointer *igraph_t as IGraph foreign finalizer igraph_destroy newtype#} --- Graph Constructors and Destructors+{#fun igraph_empty as igraphNew' { +, `Int', `Bool' } -> `IGraph' #} -{#fun igraph_empty as igraphNew' { +, `Int', `Bool' } -> `IGraphPtr' #}+{#fun igraph_copy as ^ { +, `IGraph' } -> `IGraph' #} -{#fun igraph_copy as ^ { +, `IGraphPtr' } -> `IGraphPtr' #}+-- | Create a igraph object and attach a finalizer+igraphNew :: Int -> Bool -> HasInit -> IO IGraph+igraphNew n directed _ = igraphNew' n directed +-------------------------------------------------------------------------------- -- Basic Query Operations+-------------------------------------------------------------------------------- -{#fun pure igraph_vcount as ^ { `IGraphPtr' } -> `Int' #}+{#fun igraph_vcount as ^ { `IGraph' } -> `Int' #} -{#fun pure igraph_ecount as ^ { `IGraphPtr' } -> `Int' #}+{#fun igraph_ecount as ^ { `IGraph' } -> `Int' #} -{#fun pure igraph_get_eid_ as igraphGetEid { `IGraphPtr', `Int', `Int', `Bool', `Bool' } -> `Int' #}+{#fun igraph_get_eid as ^+ { `IGraph'+ , alloca- `Int' peekIntConv*+ , `Int'+ , `Int'+ , `Bool'+ , `Bool'+ } -> `CInt' void-#} -{#fun igraph_edge as igraphEdge' { `IGraphPtr', `Int', id `Ptr CInt', id `Ptr CInt' } -> `Int' #}-igraphEdge :: IGraphPtr -> Int -> IO (Int, Int)-igraphEdge g i = alloca $ \fr -> alloca $ \to -> do- igraphEdge' g i fr to- fr' <- peek fr- to' <- peek to- return (fromIntegral fr', fromIntegral to')+{#fun igraph_edge as ^+ { `IGraph'+ , `Int'+ , alloca- `Int' peekIntConv*+ , alloca- `Int' peekIntConv*+ } -> `CInt' void-#} -- Adding and Deleting Vertices and Edges -{# fun igraph_add_vertices as ^ { `IGraphPtr', `Int', id `Ptr ()' } -> `()' #}+{# fun igraph_add_vertices as ^ { `IGraph', `Int', id `Ptr ()' } -> `()' #} -{# fun igraph_add_edge as ^ { `IGraphPtr', `Int', `Int' } -> `()' #}+{# fun igraph_add_edge as ^ { `IGraph', `Int', `Int' } -> `()' #} -{# fun igraph_add_edges as ^ { `IGraphPtr', `VectorPtr', id `Ptr ()' } -> `()' #}+-- | The edges are given in a vector, the first two elements define the first+-- edge (the order is from , to for directed graphs). The vector should+-- contain even number of integer numbers between zero and the number of+-- vertices in the graph minus one (inclusive). If you also want to add+-- new vertices, call igraph_add_vertices() first.+{# fun igraph_add_edges as ^+ { `IGraph' -- ^ The graph to which the edges will be added.+ , `Vector' -- ^ The edges themselves.+ , id `Ptr ()' -- ^ The attributes of the new edges.+ } -> `()' #} -- generators -{#fun igraph_full as ^ { +, `Int', `Bool', `Bool' } -> `IGraphPtr' #}+{#fun igraph_full as ^ { +, `Int', `Bool', `Bool' } -> `IGraph' #} {#fun igraph_erdos_renyi_game as ^ { +, `ErdosRenyi', `Int', `Double', `Bool'- , `Bool'} -> `IGraphPtr' #}- -{#fun igraph_isoclass_create as ^ { +, `Int', `Int', `Bool' } -> `IGraphPtr' #}+ , `Bool' } -> `IGraph' #}++{#fun igraph_degree_sequence_game as ^ { +, `Vector', `Vector'+ , `Degseq' } -> `IGraph' #}++{#fun igraph_rewire as ^ { `IGraph', `Int', `Rewiring' } -> `Int' #}+++{#fun igraph_isoclass_create as ^ { +, `Int', `Int', `Bool' } -> `IGraph' #}
src/IGraph/Internal/Initialization.chs view
@@ -1,7 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-} module IGraph.Internal.Initialization where -#include "haskelligraph.h"+#include "haskell_igraph.h" data HasInit
src/IGraph/Internal/Isomorphism.chs view
@@ -7,12 +7,12 @@ {#import IGraph.Internal.Graph #} {#import IGraph.Internal.Data #} -#include "igraph/igraph.h"+#include "haskell_igraph.h" -{#fun igraph_get_subisomorphisms_vf2 as ^ { `IGraphPtr', `IGraphPtr',- id `Ptr ()', id `Ptr ()', id `Ptr ()', id `Ptr ()', `VectorPPtr',- id `FunPtr (Ptr IGraphPtr -> Ptr IGraphPtr -> CInt -> CInt -> Ptr () -> IO CInt)',- id `FunPtr (Ptr IGraphPtr -> Ptr IGraphPtr -> CInt -> CInt -> Ptr () -> IO CInt)',+{#fun igraph_get_subisomorphisms_vf2 as ^ { `IGraph', `IGraph',+ id `Ptr ()', id `Ptr ()', id `Ptr ()', id `Ptr ()', `VectorPtr',+ id `FunPtr (Ptr IGraph -> Ptr IGraph -> CInt -> CInt -> Ptr () -> IO CInt)',+ id `FunPtr (Ptr IGraph -> Ptr IGraph -> CInt -> CInt -> Ptr () -> IO CInt)', id `Ptr ()'} -> `Int' #} -{#fun igraph_isomorphic as ^ { `IGraphPtr', `IGraphPtr', id `Ptr CInt' } -> `Int' #}+{#fun igraph_isomorphic as ^ { `IGraph', `IGraph', id `Ptr CInt' } -> `Int' #}
src/IGraph/Internal/Layout.chs view
@@ -12,22 +12,22 @@ #include "igraph/igraph.h" -{#fun igraph_layout_kamada_kawai as ^ { `IGraphPtr'-, `MatrixPtr'+{#fun igraph_layout_kamada_kawai as ^ { `IGraph'+, `Matrix' , `Int' , `Double' , `Double' , `Double' , `Double' , `Bool'-, id `Ptr VectorPtr'-, id `Ptr VectorPtr'-, id `Ptr VectorPtr'-, id `Ptr VectorPtr'+, id `Ptr Vector'+, id `Ptr Vector'+, id `Ptr Vector'+, id `Ptr Vector' } -> `Int' #} -{# fun igraph_layout_lgl as ^ { `IGraphPtr'-, `MatrixPtr'+{# fun igraph_layout_lgl as ^ { `IGraph'+, `Matrix' , `Int' , `Double' , `Double'
src/IGraph/Internal/Motif.chs view
@@ -11,10 +11,10 @@ {#import IGraph.Internal.Constants #} {#import IGraph.Internal.Data #} -#include "igraph/igraph.h"+#include "haskell_igraph.h" -{#fun igraph_triad_census as ^ { `IGraphPtr'- , `VectorPtr' } -> `Int' #}+{#fun igraph_triad_census as ^ { `IGraph'+ , `Vector' } -> `Int' #} -{#fun igraph_motifs_randesu as ^ { `IGraphPtr', `VectorPtr', `Int'- , `VectorPtr' } -> `Int' #}+{#fun igraph_motifs_randesu as ^ { `IGraph', `Vector', `Int'+ , `Vector' } -> `Int' #}
src/IGraph/Internal/Selector.chs view
@@ -10,28 +10,22 @@ {#import IGraph.Internal.Graph #} {#import IGraph.Internal.Data #} -#include "igraph/igraph.h"+#include "haskell_igraph.h" -{#pointer *igraph_vs_t as IGraphVsPtr foreign finalizer igraph_vs_destroy newtype #}+{#pointer *igraph_vs_t as IGraphVs foreign finalizer igraph_vs_destroy newtype #} -{#fun igraph_vs_all as ^ { + } -> `IGraphVsPtr' #}+{#fun igraph_vs_all as ^ { + } -> `IGraphVs' #} -{#fun igraph_vs_adj as ^ { +, `Int', `Neimode' } -> `IGraphVsPtr' #}+{#fun igraph_vs_adj as ^ { +, `Int', `Neimode' } -> `IGraphVs' #} -{#fun igraph_vs_vector as ^ { +, `VectorPtr' } -> `IGraphVsPtr' #}+{#fun igraph_vs_vector as ^ { +, `Vector' } -> `IGraphVs' #} -- Vertex iterator -{#pointer *igraph_vit_t as IGraphVitPtr foreign finalizer igraph_vit_destroy newtype #}+{#pointer *igraph_vit_t as IGraphVit foreign finalizer igraph_vit_destroy newtype #} #c-igraph_vit_t* igraph_vit_new(const igraph_t *graph, igraph_vs_t vs) {- igraph_vit_t* vit = (igraph_vit_t*) malloc (sizeof (igraph_vit_t));- igraph_vit_create(graph, vs, vit);- return vit;-}- igraph_bool_t igraph_vit_end(igraph_vit_t *vit) { return IGRAPH_VIT_END(*vit); }@@ -45,15 +39,15 @@ } #endc -{#fun igraph_vit_new as ^ { `IGraphPtr', %`IGraphVsPtr' } -> `IGraphVitPtr' #}+{#fun igraph_vit_create as igraphVitNew { `IGraph', %`IGraphVs', + } -> `IGraphVit' #} -{#fun igraph_vit_end as ^ { `IGraphVitPtr' } -> `Bool' #}+{#fun igraph_vit_end as ^ { `IGraphVit' } -> `Bool' #} -{#fun igraph_vit_next as ^ { `IGraphVitPtr' } -> `()' #}+{#fun igraph_vit_next as ^ { `IGraphVit' } -> `()' #} -{#fun igraph_vit_get as ^ { `IGraphVitPtr' } -> `Int' #}+{#fun igraph_vit_get as ^ { `IGraphVit' } -> `Int' #} -vitToList :: IGraphVitPtr -> IO [Int]+vitToList :: IGraphVit -> IO [Int] vitToList vit = do isEnd <- igraphVitEnd vit if isEnd@@ -67,24 +61,18 @@ -- Edge Selector -{#pointer *igraph_es_t as IGraphEsPtr foreign finalizer igraph_es_destroy newtype #}+{#pointer *igraph_es_t as IGraphEs foreign finalizer igraph_es_destroy newtype #} -{#fun igraph_es_all as ^ { +, `EdgeOrderType' } -> `IGraphEsPtr' #}+{#fun igraph_es_all as ^ { +, `EdgeOrderType' } -> `IGraphEs' #} -{# fun igraph_es_vector as ^ { +, `VectorPtr' } -> `IGraphEsPtr' #}+{# fun igraph_es_vector as ^ { +, `Vector' } -> `IGraphEs' #} -- Edge iterator -{#pointer *igraph_eit_t as IGraphEitPtr foreign finalizer igraph_eit_destroy newtype #}+{#pointer *igraph_eit_t as IGraphEit foreign finalizer igraph_eit_destroy newtype #} #c-igraph_eit_t* igraph_eit_new(const igraph_t *graph, igraph_es_t es) {- igraph_eit_t* eit = (igraph_eit_t*) malloc (sizeof (igraph_eit_t));- igraph_eit_create(graph, es, eit);- return eit;-}- igraph_bool_t igraph_eit_end(igraph_eit_t *eit) { return IGRAPH_EIT_END(*eit); }@@ -98,15 +86,15 @@ } #endc -{#fun igraph_eit_new as ^ { `IGraphPtr', %`IGraphEsPtr' } -> `IGraphEitPtr' #}+{#fun igraph_eit_create as igraphEitNew { `IGraph', %`IGraphEs', + } -> `IGraphEit' #} -{#fun igraph_eit_end as ^ { `IGraphEitPtr' } -> `Bool' #}+{#fun igraph_eit_end as ^ { `IGraphEit' } -> `Bool' #} -{#fun igraph_eit_next as ^ { `IGraphEitPtr' } -> `()' #}+{#fun igraph_eit_next as ^ { `IGraphEit' } -> `()' #} -{#fun igraph_eit_get as ^ { `IGraphEitPtr' } -> `Int' #}+{#fun igraph_eit_get as ^ { `IGraphEit' } -> `Int' #} -eitToList :: IGraphEitPtr -> IO [Int]+eitToList :: IGraphEit -> IO [Int] eitToList eit = do isEnd <- igraphEitEnd eit if isEnd@@ -119,9 +107,9 @@ -- delete vertices -{# fun igraph_delete_vertices as ^ { `IGraphPtr', %`IGraphVsPtr' } -> `Int' #}+{# fun igraph_delete_vertices as ^ { `IGraph', %`IGraphVs' } -> `Int' #} -- delete edges -{# fun igraph_delete_edges as ^ { `IGraphPtr', %`IGraphEsPtr' } -> `Int' #}+{# fun igraph_delete_edges as ^ { `IGraph', %`IGraphEs' } -> `Int' #}
src/IGraph/Internal/Structure.chs view
@@ -12,50 +12,50 @@ #include "igraph/igraph.h" -{#fun igraph_induced_subgraph as ^ { `IGraphPtr'- , id `Ptr (IGraphPtr)'- , %`IGraphVsPtr'- , `SubgraphImplementation' } -> `Int' #}+{#fun igraph_induced_subgraph as ^ { `IGraph'+ , +160+ , %`IGraphVs'+ , `SubgraphImplementation' } -> `IGraph' #} -{#fun igraph_closeness as ^ { `IGraphPtr'- , `VectorPtr'- , %`IGraphVsPtr'+{#fun igraph_closeness as ^ { `IGraph'+ , `Vector'+ , %`IGraphVs' , `Neimode'- , `VectorPtr'+ , `Vector' , `Bool' } -> `Int' #} -{#fun igraph_betweenness as ^ { `IGraphPtr'- , `VectorPtr'- , %`IGraphVsPtr'+{#fun igraph_betweenness as ^ { `IGraph'+ , `Vector'+ , %`IGraphVs' , `Bool'- , `VectorPtr'+ , `Vector' , `Bool' } -> `Int' #} -{#fun igraph_eigenvector_centrality as ^ { `IGraphPtr'- , `VectorPtr'+{#fun igraph_eigenvector_centrality as ^ { `IGraph'+ , `Vector' , id `Ptr CDouble' , `Bool' , `Bool'- , `VectorPtr'- , `ArpackOptPtr' } -> `Int' #}+ , `Vector'+ , `ArpackOpt' } -> `Int' #} -{#fun igraph_pagerank as ^ { `IGraphPtr'+{#fun igraph_pagerank as ^ { `IGraph' , `PagerankAlgo'- , `VectorPtr'+ , `Vector' , id `Ptr CDouble'- , %`IGraphVsPtr'+ , %`IGraphVs' , `Bool' , `Double'- , `VectorPtr'+ , `Vector' , id `Ptr ()' } -> `Int' #} -{#fun igraph_personalized_pagerank as ^ { `IGraphPtr'+{#fun igraph_personalized_pagerank as ^ { `IGraph' , `PagerankAlgo'- , `VectorPtr'+ , `Vector' , id `Ptr CDouble'- , %`IGraphVsPtr'+ , %`IGraphVs' , `Bool' , `Double'- , `VectorPtr'- , `VectorPtr'+ , `Vector'+ , `Vector' , id `Ptr ()' } -> `Int' #}
src/IGraph/Isomorphism.hs view
@@ -25,7 +25,7 @@ vpptr <- igraphVectorPtrNew 0 igraphGetSubisomorphismsVf2 gptr1 gptr2 nullPtr nullPtr nullPtr nullPtr vpptr nullFunPtr nullFunPtr nullPtr- (map.map) truncate <$> vectorPPtrToList vpptr+ (map.map) truncate <$> toLists vpptr where gptr1 = _graph g1 gptr2 = _graph g2
src/IGraph/Layout.hs view
@@ -41,7 +41,7 @@ defaultKamadaKawai :: LayoutMethod defaultKamadaKawai = KamadaKawai { kk_seed = Nothing- , kk_nIter = 1000+ , kk_nIter = 10 , kk_sigma = \x -> fromIntegral x / 4 , kk_startTemp = 10 , kk_coolFact = 0.99@@ -50,7 +50,7 @@ defaultLGL :: LayoutMethod defaultLGL = LGL- { lgl_nIter = 150+ { lgl_nIter = 100 , lgl_maxdelta = \x -> fromIntegral x , lgl_area = area , lgl_coolexp = 1.5@@ -68,18 +68,18 @@ Nothing -> igraphMatrixNew 0 0 Just xs -> if length xs /= nNodes gr then error "Seed error: incorrect size"- else listsToMatrixPtr $ (\(x,y) -> [x,y]) $ unzip xs+ else fromRowLists $ (\(x,y) -> [x,y]) $ unzip xs igraphLayoutKamadaKawai gptr mptr niter (sigma n) initemp coolexp (kkconst n) (isJust seed) nullPtr nullPtr nullPtr nullPtr- [x, y] <- matrixPtrToColumnLists mptr+ [x, y] <- toColumnLists mptr return $ zip x y LGL niter delta area coolexp repulserad cellsize -> do mptr <- igraphMatrixNew 0 0 igraphLayoutLgl gptr mptr niter (delta n) (area n) coolexp (repulserad n) (cellsize n) (-1)- [x, y] <- matrixPtrToColumnLists mptr+ [x, y] <- toColumnLists mptr return $ zip x y where n = nNodes gr
src/IGraph/Motif.hs view
@@ -55,6 +55,6 @@ triadCensus gr = unsafePerformIO $ do vptr <- igraphVectorNew 0 igraphTriadCensus (_graph gr) vptr- map truncate <$> vectorPtrToList vptr+ map truncate <$> toList vptr -- motifsRandesu
src/IGraph/Mutable.hs view
@@ -1,132 +1,134 @@ {-# LANGUAGE MultiParamTypeClasses #-}-module IGraph.Mutable where+module IGraph.Mutable+ ( MGraph(..)+ , MLGraph(..)+ , setEdgeAttr+ , setNodeAttr+ , edgeAttr+ , vertexAttr+ , withVertexAttr+ , withEdgeAttr+ )where -import Control.Monad (when)+import Control.Monad (when, forM) import Control.Monad.Primitive import qualified Data.ByteString.Char8 as B+import Data.Serialize (Serialize) import Foreign+import Foreign.C.String (CString, withCString) import IGraph.Internal.Attribute import IGraph.Internal.Data import IGraph.Internal.Graph import IGraph.Internal.Initialization import IGraph.Internal.Selector+import IGraph.Types --- constants vertexAttr :: String vertexAttr = "vertex_attribute" edgeAttr :: String edgeAttr = "edge_attribute" -type LEdge a = (Int, Int, a)+withVertexAttr :: (CString -> IO a) -> IO a+withVertexAttr = withCString vertexAttr+{-# INLINE withVertexAttr #-} --- | Mutable labeled graph-newtype MLGraph m d v e = MLGraph IGraphPtr+withEdgeAttr :: (CString -> IO a) -> IO a+withEdgeAttr = withCString edgeAttr+{-# INLINE withEdgeAttr #-} +-- | Mutable labeled graph.+newtype MLGraph m d v e = MLGraph IGraph+ class MGraph d where+ -- | Create a new graph. new :: PrimMonad m => Int -> m (MLGraph (PrimState m) d v e) - addNodes :: PrimMonad m => Int -> MLGraph(PrimState m) d v e -> m ()+ -- | Add nodes to the graph.+ addNodes :: PrimMonad m+ => Int -- ^ The number of new nodes.+ -> MLGraph(PrimState m) d v e -> m () addNodes n (MLGraph g) = unsafePrimToPrim $ igraphAddVertices g n nullPtr - addLNodes :: (Show v, PrimMonad m)- => Int -- ^ the number of new vertices add to the graph- -> [v] -- ^ vertices' labels- -> MLGraph (PrimState m) d v e -> m ()- addLNodes n labels (MLGraph g)- | n /= length labels = error "addLVertices: incorrect number of labels"- | otherwise = unsafePrimToPrim $ do- let attr = makeAttributeRecord vertexAttr labels- alloca $ \ptr -> do- poke ptr attr- vptr <- listToVectorP [castPtr ptr]- withVectorPPtr vptr $ \p -> igraphAddVertices g n $ castPtr p+ -- | Add nodes with labels to the graph.+ addLNodes :: (Serialize v, PrimMonad m)+ => [v] -- ^ vertices' labels+ -> MLGraph (PrimState m) d v e -> m ()+ addLNodes labels (MLGraph g) = unsafePrimToPrim $ withVertexAttr $+ \vattr -> asBSVector labels $ \bsvec -> with (mkStrRec vattr bsvec) $+ \ptr -> do vptr <- fromPtrs [castPtr ptr]+ withVectorPtr vptr (igraphAddVertices g n . castPtr)+ where+ n = length labels + -- | Delete nodes from the graph. delNodes :: PrimMonad m => [Int] -> MLGraph (PrimState m) d v e -> m () delNodes ns (MLGraph g) = unsafePrimToPrim $ do- vptr <- listToVector $ map fromIntegral ns+ vptr <- fromList $ map fromIntegral ns vsptr <- igraphVsVector vptr igraphDeleteVertices g vsptr return () + -- | Add edges to the graph. addEdges :: PrimMonad m => [(Int, Int)] -> MLGraph (PrimState m) d v e -> m ()-- addLEdges :: (PrimMonad m, Show e) => [LEdge e] -> MLGraph (PrimState m) d v e -> m ()-- delEdges :: PrimMonad m => [(Int, Int)] -> MLGraph (PrimState m) d v e -> m ()--data U = U-data D = D--instance MGraph U where- new n = unsafePrimToPrim $ igraphInit >>= igraphNew n False >>= return . MLGraph- addEdges es (MLGraph g) = unsafePrimToPrim $ do- vec <- listToVector xs+ vec <- fromList xs igraphAddEdges g vec nullPtr where xs = concatMap ( \(a,b) -> [fromIntegral a, fromIntegral b] ) es - addLEdges es (MLGraph g) = unsafePrimToPrim $ do- vec <- listToVector $ concat xs- let attr = makeAttributeRecord edgeAttr vs- alloca $ \ptr -> do- poke ptr attr- vptr <- listToVectorP [castPtr ptr]- withVectorPPtr vptr $ \p -> igraphAddEdges g vec $ castPtr p+ -- | Add edges with labels to the graph.+ addLEdges :: (PrimMonad m, Serialize e) => [LEdge e] -> MLGraph (PrimState m) d v e -> m ()+ addLEdges es (MLGraph g) = unsafePrimToPrim $ withEdgeAttr $ \eattr ->+ asBSVector vs $ \bsvec -> with (mkStrRec eattr bsvec) $ \ptr -> do+ vec <- fromList $ concat xs+ vptr <- fromPtrs [castPtr ptr]+ withVectorPtr vptr (igraphAddEdges g vec . castPtr) where- (xs, vs) = unzip $ map ( \(a,b,v) -> ([fromIntegral a, fromIntegral b], v) ) es+ (xs, vs) = unzip $ map ( \((a,b),v) -> ([fromIntegral a, fromIntegral b], v) ) es + -- | Delete edges from the graph.+ delEdges :: PrimMonad m => [(Int, Int)] -> MLGraph (PrimState m) d v e -> m ()++instance MGraph U where+ new n = unsafePrimToPrim $ igraphInit >>= igraphNew n False >>= return . MLGraph+ delEdges es (MLGraph g) = unsafePrimToPrim $ do- vptr <- listToVector $ map fromIntegral eids+ eids <- forM es $ \(fr, to) -> igraphGetEid g fr to False True+ vptr <- fromList $ map fromIntegral eids esptr <- igraphEsVector vptr igraphDeleteEdges g esptr return ()- where- eids = flip map es $ \(fr, to) -> igraphGetEid g fr to False True instance MGraph D where new n = unsafePrimToPrim $ igraphInit >>= igraphNew n True >>= return . MLGraph - addEdges es (MLGraph g) = unsafePrimToPrim $ do- vec <- listToVector xs- igraphAddEdges g vec nullPtr- where- xs = concatMap ( \(a,b) -> [fromIntegral a, fromIntegral b] ) es-- addLEdges es (MLGraph g) = unsafePrimToPrim $ do- vec <- listToVector $ concat xs- let attr = makeAttributeRecord edgeAttr vs- alloca $ \ptr -> do- poke ptr attr- vptr <- listToVectorP [castPtr ptr]- withVectorPPtr vptr $ \p -> igraphAddEdges g vec $ castPtr p- where- (xs, vs) = unzip $ map ( \(a,b,v) -> ([fromIntegral a, fromIntegral b], v) ) es- delEdges es (MLGraph g) = unsafePrimToPrim $ do- vptr <- listToVector $ map fromIntegral eids+ eids <- forM es $ \(fr, to) -> igraphGetEid g fr to True True+ vptr <- fromList $ map fromIntegral eids esptr <- igraphEsVector vptr igraphDeleteEdges g esptr return ()- where- eids = flip map es $ \(fr, to) -> igraphGetEid g fr to True True -setNodeAttr :: (PrimMonad m, Show v)+-- | Set node attribute.+setNodeAttr :: (PrimMonad m, Serialize v) => Int -- ^ Node id -> v -> MLGraph (PrimState m) d v e -> m ()-setNodeAttr nodeId x (MLGraph gr) = unsafePrimToPrim $ do- err <- igraphCattributeVASSet gr vertexAttr nodeId $ show x- when (err /= 0) $ error "Fail to set node attribute!"+setNodeAttr nodeId x (MLGraph gr) = unsafePrimToPrim $ asBS x $ \bs ->+ with bs $ \bsptr -> do+ err <- igraphHaskellAttributeVASSet gr vertexAttr nodeId bsptr+ when (err /= 0) $ error "Fail to set node attribute!" -setEdgeAttr :: (PrimMonad m, Show v)+-- | Set edge attribute.+setEdgeAttr :: (PrimMonad m, Serialize e) => Int -- ^ Edge id- -> v+ -> e -> MLGraph (PrimState m) d v e -> m ()-setEdgeAttr edgeId x (MLGraph gr) = unsafePrimToPrim $ do- err <- igraphCattributeEASSet gr edgeAttr edgeId $ show x- when (err /= 0) $ error "Fail to set edge attribute!"+setEdgeAttr edgeId x (MLGraph gr) = unsafePrimToPrim $ asBS x $ \bs ->+ with bs $ \bsptr -> do+ err <- igraphHaskellAttributeEASSet gr edgeAttr edgeId bsptr+ when (err /= 0) $ error "Fail to set edge attribute!"
src/IGraph/Structure.hs view
@@ -7,36 +7,35 @@ , personalizedPagerank ) where -import Control.Monad-import Foreign-import Foreign.C.Types-import System.IO.Unsafe (unsafePerformIO)-import qualified Data.HashMap.Strict as M-import Data.Hashable (Hashable)+import Control.Monad+import Data.Hashable (Hashable)+import qualified Data.HashMap.Strict as M+import Data.Serialize (Serialize)+import Foreign+import Foreign.C.Types+import System.IO.Unsafe (unsafePerformIO) -import IGraph-import IGraph.Mutable-import IGraph.Internal.Graph-import IGraph.Internal.Data-import IGraph.Internal.Selector-import IGraph.Internal.Structure-import IGraph.Internal.Arpack-import IGraph.Internal.Constants-import IGraph.Internal.Attribute+import IGraph+import IGraph.Internal.Arpack+import IGraph.Internal.Attribute+import IGraph.Internal.Constants+import IGraph.Internal.Data+import IGraph.Internal.Graph+import IGraph.Internal.Selector+import IGraph.Internal.Structure+import IGraph.Mutable -inducedSubgraph :: (Hashable v, Eq v, Read v) => LGraph d v e -> [Int] -> LGraph d v e+inducedSubgraph :: (Hashable v, Eq v, Serialize v) => LGraph d v e -> [Int] -> LGraph d v e inducedSubgraph gr vs = unsafePerformIO $ do- vs' <- listToVector $ map fromIntegral vs+ vs' <- fromList $ map fromIntegral vs vsptr <- igraphVsVector vs'- mallocForeignPtrBytes 160 >>= \gptr -> withForeignPtr gptr $ \p -> do- igraphInducedSubgraph (_graph gr) p vsptr IgraphSubgraphCreateFromScratch- let g' = IGraphPtr gptr- labToId = M.fromListWith (++) $ zip labels $ map return [0..nV-1]- nV = igraphVcount g'- labels = map (read . igraphCattributeVAS g' vertexAttr) [0 .. nV-1]- return $ LGraph g' labToId+ g' <- igraphInducedSubgraph (_graph gr) vsptr IgraphSubgraphCreateFromScratch+ nV <- igraphVcount g'+ labels <- forM [0 .. nV - 1] $ \i ->+ igraphHaskellAttributeVAS g' vertexAttr i >>= fromBS+ return $ LGraph g' $ M.fromListWith (++) $ zip labels $ map return [0..nV-1] --- | closeness centrality+-- | Closeness centrality closeness :: [Int] -- ^ vertices -> LGraph d v e -> Maybe [Double] -- ^ optional edge weights@@ -44,42 +43,42 @@ -> Bool -- ^ whether to normalize -> [Double] closeness vs gr ws mode normal = unsafePerformIO $ do- vs' <- listToVector $ map fromIntegral vs+ vs' <- fromList $ map fromIntegral vs vsptr <- igraphVsVector vs' vptr <- igraphVectorNew 0 ws' <- case ws of- Just w -> listToVector w- _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr+ Just w -> fromList w+ _ -> liftM Vector $ newForeignPtr_ $ castPtr nullPtr igraphCloseness (_graph gr) vptr vsptr mode ws' normal- vectorPtrToList vptr+ toList vptr --- | betweenness centrality+-- | Betweenness centrality betweenness :: [Int] -> LGraph d v e -> Maybe [Double] -> [Double] betweenness vs gr ws = unsafePerformIO $ do- vs' <- listToVector $ map fromIntegral vs+ vs' <- fromList $ map fromIntegral vs vsptr <- igraphVsVector vs' vptr <- igraphVectorNew 0 ws' <- case ws of- Just w -> listToVector w- _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr+ Just w -> fromList w+ _ -> liftM Vector $ newForeignPtr_ $ castPtr nullPtr igraphBetweenness (_graph gr) vptr vsptr True ws' False- vectorPtrToList vptr+ toList vptr --- | eigenvector centrality+-- | Eigenvector centrality eigenvectorCentrality :: LGraph d v e -> Maybe [Double] -> [Double] eigenvectorCentrality gr ws = unsafePerformIO $ do vptr <- igraphVectorNew 0 ws' <- case ws of- Just w -> listToVector w- _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr+ Just w -> fromList w+ _ -> liftM Vector $ newForeignPtr_ $ castPtr nullPtr arparck <- igraphArpackNew igraphEigenvectorCentrality (_graph gr) vptr nullPtr True True ws' arparck- vectorPtrToList vptr+ toList vptr -- | Google's PageRank pagerank :: Graph d@@ -87,29 +86,45 @@ -> Maybe [Double] -- ^ edge weights -> Double -- ^ damping factor, usually around 0.85 -> [Double]-pagerank gr ws d = unsafePerformIO $ alloca $ \p -> do- vptr <- igraphVectorNew 0- vsptr <- igraphVsAll- ws' <- case ws of- Just w -> listToVector w- _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr- igraphPagerank (_graph gr) IgraphPagerankAlgoPrpack vptr p vsptr- (isDirected gr) d ws' nullPtr- vectorPtrToList vptr+pagerank gr ws d+ | n == 0 = []+ | otherwise = unsafePerformIO $ alloca $ \p -> do+ vptr <- igraphVectorNew 0+ vsptr <- igraphVsAll+ ws' <- case ws of+ Just w -> if length w /= m+ then error "pagerank: incorrect length of edge weight vector"+ else fromList w+ _ -> liftM Vector $ newForeignPtr_ $ castPtr nullPtr+ igraphPagerank (_graph gr) IgraphPagerankAlgoPrpack vptr p vsptr+ (isDirected gr) d ws' nullPtr+ toList vptr+ where+ n = nNodes gr+ m = nEdges gr +-- | Personalized PageRank. personalizedPagerank :: Graph d => LGraph d v e -> [Double] -- ^ reset probability -> Maybe [Double] -> Double -> [Double]-personalizedPagerank gr reset ws d = unsafePerformIO $ alloca $ \p -> do- vptr <- igraphVectorNew 0- vsptr <- igraphVsAll- ws' <- case ws of- Just w -> listToVector w- _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr- reset' <- listToVector reset- igraphPersonalizedPagerank (_graph gr) IgraphPagerankAlgoPrpack vptr p vsptr- (isDirected gr) d reset' ws' nullPtr- vectorPtrToList vptr+personalizedPagerank gr reset ws d+ | n == 0 = []+ | length reset /= n = error "personalizedPagerank: incorrect length of reset vector"+ | otherwise = unsafePerformIO $ alloca $ \p -> do+ vptr <- igraphVectorNew 0+ vsptr <- igraphVsAll+ ws' <- case ws of+ Just w -> if length w /= m+ then error "pagerank: incorrect length of edge weight vector"+ else fromList w+ _ -> liftM Vector $ newForeignPtr_ $ castPtr nullPtr+ reset' <- fromList reset+ igraphPersonalizedPagerank (_graph gr) IgraphPagerankAlgoPrpack vptr p vsptr+ (isDirected gr) d reset' ws' nullPtr+ toList vptr+ where+ n = nNodes gr+ m = nEdges gr
+ src/IGraph/Types.hs view
@@ -0,0 +1,16 @@++module IGraph.Types where++import qualified Data.HashMap.Strict as M++import IGraph.Internal.Graph++type Node = Int+type Edge = (Node, Node)+type LEdge a = (Edge, a)++-- | Undirected graph.+data U++-- | Directed graph.+data D
+ tests/Test/Attributes.hs view
@@ -0,0 +1,60 @@+module Test.Attributes+ ( tests+ ) where++import Conduit+import Control.Monad+import Control.Monad.ST+import Data.List+import Data.List.Ordered (nubSort)+import Data.Maybe+import Data.Serialize+import Foreign+import System.IO.Unsafe+import Test.Tasty+import Test.Tasty.HUnit+import Test.Utils++import IGraph+import IGraph.Exporter.GEXF+import IGraph.Internal.Attribute+import IGraph.Mutable+import IGraph.Structure++tests :: TestTree+tests = testGroup "Attribute tests"+ [ nodeLabelTest+ , labelTest+ , serializeTest+ ]++nodeLabelTest :: TestTree+nodeLabelTest = testCase "node label test" $ do+ let ns = sort $ map show [38..7000]+ gr = mkGraph ns [] :: LGraph D String ()+ assertBool "" $ sort (map (nodeLab gr) $ nodes gr) == ns++labelTest :: TestTree+labelTest = testCase "edge label test" $ do+ dat <- randEdges 1000 10000+ let es = sort $ zipWith (\a b -> (a,b)) dat $ map show [1..]+ gr = fromLabeledEdges es :: LGraph D Int String+ es' = sort $ map (\(a,b) -> ((nodeLab gr a, nodeLab gr b), edgeLab gr (a,b))) $ edges gr+ assertBool "" $ es == es'++serializeTest :: TestTree+serializeTest = testCase "serialize test" $ do+ dat <- randEdges 1000 10000+ let es = map ( \(a, b) -> (+ ( defaultNodeAttributes{_nodeZindex=a}+ , defaultNodeAttributes{_nodeZindex=b}), defaultEdgeAttributes) ) dat+ gr = fromLabeledEdges es :: LGraph D NodeAttr EdgeAttr+ gr' :: LGraph D NodeAttr EdgeAttr+ gr' = case decode $ encode gr of+ Left msg -> error msg+ Right r -> r+ es' = map (\(a,b) -> ((nodeLab gr' a, nodeLab gr' b), edgeLab gr' (a,b))) $ edges gr'+ gr'' <- runConduit $ (yield $ encode gr) .| decodeC :: IO (LGraph D NodeAttr EdgeAttr)+ let es'' = map (\(a,b) -> ((nodeLab gr'' a, nodeLab gr'' b), edgeLab gr'' (a,b))) $ edges gr''+ assertBool "" $ sort (map show es) == sort (map show es') &&+ sort (map show es) == sort (map show es'')
tests/Test/Basic.hs view
@@ -10,6 +10,7 @@ import Test.Tasty import Test.Tasty.HUnit import Test.Utils+import Conduit import IGraph import IGraph.Mutable@@ -39,14 +40,17 @@ graphCreationLabeled = testGroup "Graph creation -- with labels" [ testCase "" $ assertBool "" $ nNodes gr == n && nEdges gr == m , testCase "" $ edgeList @=? (sort $ map (\(fr,to) ->- (nodeLab gr fr, nodeLab gr to)) $ edges gr)+ ((nodeLab gr fr, nodeLab gr to), edgeLab gr (fr, to))) $ edges gr)+ , testCase "" $ edgeList @=? (sort $ map (\(fr,to) ->+ ((nodeLab gr' fr, nodeLab gr' to), edgeLab gr' (fr, to))) $ edges gr') ] where- edgeList = sort $ map (\(a,b) -> (show a, show b)) $ unsafePerformIO $ randEdges 10000 1000- n = length $ nubSort $ concatMap (\(a,b) -> [a,b]) edgeList+ edgeList = zip (sort $ map (\(a,b) -> (show a, show b)) $ unsafePerformIO $+ randEdges 10000 1000) $ repeat 1+ n = length $ nubSort $ concatMap (\((a,b),_) -> [a,b]) edgeList m = length edgeList- gr = fromLabeledEdges $ zip edgeList $ repeat () :: LGraph D String ()-+ gr = fromLabeledEdges edgeList :: LGraph D String Int+ gr' = runST $ fromLabeledEdges' edgeList yieldMany :: LGraph D String Int graphEdit :: TestTree graphEdit = testGroup "Graph editing"
tests/test.hs view
@@ -2,6 +2,7 @@ import qualified Test.Isomorphism as Isomorphism import qualified Test.Motif as Motif import qualified Test.Structure as Structure+import qualified Test.Attributes as Attributes import Test.Tasty main :: IO ()@@ -10,4 +11,5 @@ , Structure.tests , Motif.tests , Isomorphism.tests+ , Attributes.tests ]