packages feed

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 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     ]