diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,7 +1,13 @@
 Revision history for haskell-igraph
 ===================================
 
-v0.8.0 -- XXXX-XX-XX
+v0.8.5 -- 2025-08-05
+--------------------
+
+* Ship igraph C sources v0.8.5
+* Add more functions
+
+v0.8.0 -- 2020-02-22
 --------------------
 
 * Ship igraph C sources v0.8.0
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2016-2020 Kai Zhang
+Copyright (c) 2016-2021 Kai Zhang
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/cbits/bytestring.c b/cbits/bytestring.c
--- a/cbits/bytestring.c
+++ b/cbits/bytestring.c
@@ -342,7 +342,7 @@
   igraph_strvector_t *str;
   size_t i;
   igraph_strvector_init(str, from->len);
-  for (i = 0; i++; i < from->len) {
+  for (i = 0; i < from->len; i++) {
     igraph_strvector_set(str, i, bytestring_to_char(from->data[i]));
   }
   return str;
@@ -352,7 +352,7 @@
   bsvector_t *str;
   size_t i;
   bsvector_init(str, from->len);
-  for (i = 0; i++; i < from->len) {
+  for (i = 0; i < from->len; i++) {
     bsvector_set(str, i, char_to_bytestring(from->data[i]));
   }
   return str;
diff --git a/cbits/bytestring.h b/cbits/bytestring.h
new file mode 100644
--- /dev/null
+++ b/cbits/bytestring.h
@@ -0,0 +1,115 @@
+#ifndef HASKELL_IGRAPH_BYTESTRING
+#define HASKELL_IGRAPH_BYTESTRING
+
+#include "igraph.h"
+
+__BEGIN_DECLS
+
+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(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);
+
+DECLDIR void bsvector_destroy(bsvector_t *sv);
+
+DECLDIR void bsvector_get(const bsvector_t *sv, long int idx, bytestring_t **value);
+
+DECLDIR int bsvector_set(bsvector_t *sv, long int idx, const bytestring_t *value);
+
+DECLDIR void bsvector_remove_section(bsvector_t *v, long int from, long int to);
+
+DECLDIR 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);
+
+__END_DECLS
+
+#endif
diff --git a/cbits/haskell_attributes.c b/cbits/haskell_attributes.c
--- a/cbits/haskell_attributes.c
+++ b/cbits/haskell_attributes.c
@@ -466,8 +466,6 @@
       }
       if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) {
 				if (ne != bsvector_size(newstr)) {
-					printf("number of edges: %d\n", ne);
-					printf("number of attributes: %d\n", bsvector_size(newstr));
 					IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL);
 				}
 				IGRAPH_CHECK(bsvector_append(oldstr, newstr));
diff --git a/cbits/haskell_attributes.h b/cbits/haskell_attributes.h
new file mode 100644
--- /dev/null
+++ b/cbits/haskell_attributes.h
@@ -0,0 +1,218 @@
+#ifndef HASKELL_IGRAPH_ATTRIBUTE
+#define HASKELL_IGRAPH_ATTRIBUTE
+
+#include "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
diff --git a/cbits/haskell_igraph.h b/cbits/haskell_igraph.h
new file mode 100644
--- /dev/null
+++ b/cbits/haskell_igraph.h
@@ -0,0 +1,8 @@
+#ifndef HASKELL_IGRAPH
+#define HASKELL_IGRAPH
+
+#include "igraph.h"
+
+void haskelligraph_init();
+
+#endif
diff --git a/haskell-igraph.cabal b/haskell-igraph.cabal
--- a/haskell-igraph.cabal
+++ b/haskell-igraph.cabal
@@ -1,653 +1,860 @@
-cabal-version:       2.2
-name:                haskell-igraph
-version:             0.8.0
-synopsis:            Bindings to the igraph C library (v0.8.0).
-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-2020 Kai Zhang
-category:            Math
-build-type:          Simple
-extra-source-files:
-  include/*.h
-  igraph/include/*.h
-  igraph/include/*.pmt
-  igraph/include/f2c/*.h
-  igraph/include/prpack/*.h
-  igraph/include/cs/*.h
-  igraph/include/cliquer/*.h
-  igraph/include/bliss/*.hh
-  igraph/include/plfit/*.h
-  igraph/AUTHORS
-  igraph/COPYING
-  stack.yaml
-  README.md
-  ChangeLog.md
-
-library
-  exposed-modules:
-    IGraph.Internal.Initialization
-    IGraph.Internal.Constants
-    IGraph.Internal
-    IGraph
-    IGraph.Mutable
-    IGraph.Random
-    IGraph.Types
-    IGraph.Algorithms
-    IGraph.Algorithms.Structure
-    IGraph.Algorithms.Community
-    IGraph.Algorithms.Clique
-    --IGraph.Algorithms.Layout
-    IGraph.Algorithms.Motif
-    IGraph.Algorithms.Generators
-    IGraph.Algorithms.Isomorphism
-    IGraph.Algorithms.Centrality
-
-  other-modules:
-    IGraph.Internal.C2HS
-
-  build-depends:
-      base >= 4.0 && < 5.0
-    , bytestring >= 0.9
-    , cereal
-    , conduit >= 1.3.0
-    , containers
-    , data-ordlist
-    , primitive
-    , singletons
-
-  extra-libraries:     stdc++
-  hs-source-dirs:      src
-  default-language:    Haskell2010
-  ghc-options:         -Wall
-  build-tool-depends: c2hs:c2hs >=0.25.0
-  c-sources:
-    cbits/haskell_igraph.c
-    cbits/haskell_attributes.c
-    cbits/bytestring.c
-
-    -- igraph
-    igraph/src/abort_.c
-    igraph/src/adjlist.c
-    igraph/src/arithchk.c
-    igraph/src/arpack.c
-    igraph/src/array.c
-    igraph/src/atlas.c
-    igraph/src/attributes.c
-    igraph/src/backspac.c
-    igraph/src/basic_query.c
-    igraph/src/bfgs.c
-    igraph/src/bigint.c
-    igraph/src/bignum.c
-    igraph/src/bipartite.c
-    igraph/src/blas.c
-    igraph/src/c_abs.c
-    igraph/src/cabs.c
-    igraph/src/cattributes.c
-    igraph/src/c_cos.c
-    igraph/src/c_div.c
-    igraph/src/centrality.c
-    igraph/src/c_exp.c
-    igraph/src/cliquer.c
-    igraph/src/cliquer_graph.c
-    igraph/src/cliques.c
-    igraph/src/c_log.c
-    igraph/src/close.c
-    igraph/src/cocitation.c
-    igraph/src/cohesive_blocks.c
-    igraph/src/coloring.c
-    igraph/src/community.c
-    igraph/src/community_leiden.c
-    igraph/src/complex.c
-    igraph/src/components.c
-    igraph/src/conversion.c
-    igraph/src/cores.c
-    igraph/src/cs_add.c
-    igraph/src/cs_amd.c
-    igraph/src/cs_chol.c
-    igraph/src/cs_cholsol.c
-    igraph/src/cs_compress.c
-    igraph/src/cs_counts.c
-    igraph/src/cs_cumsum.c
-    igraph/src/cs_dfs.c
-    igraph/src/cs_dmperm.c
-    igraph/src/cs_droptol.c
-    igraph/src/cs_dropzeros.c
-    igraph/src/cs_dupl.c
-    igraph/src/cs_entry.c
-    igraph/src/cs_ereach.c
-    igraph/src/cs_etree.c
-    igraph/src/cs_fkeep.c
-    igraph/src/cs_gaxpy.c
-    igraph/src/cs_happly.c
-    igraph/src/cs_house.c
-    igraph/src/c_sin.c
-    igraph/src/cs_ipvec.c
-    igraph/src/cs_leaf.c
-    igraph/src/cs_load.c
-    igraph/src/cs_lsolve.c
-    igraph/src/cs_ltsolve.c
-    igraph/src/cs_lu.c
-    igraph/src/cs_lusol.c
-    igraph/src/cs_malloc.c
-    igraph/src/cs_maxtrans.c
-    igraph/src/cs_multiply.c
-    igraph/src/cs_norm.c
-    igraph/src/cs_permute.c
-    igraph/src/cs_pinv.c
-    igraph/src/cs_post.c
-    igraph/src/cs_print.c
-    igraph/src/cs_pvec.c
-    igraph/src/cs_qr.c
-    igraph/src/cs_qrsol.c
-    igraph/src/c_sqrt.c
-    igraph/src/cs_randperm.c
-    igraph/src/cs_reach.c
-    igraph/src/cs_scatter.c
-    igraph/src/cs_scc.c
-    igraph/src/cs_schol.c
-    igraph/src/cs_spsolve.c
-    igraph/src/cs_sqr.c
-    igraph/src/cs_symperm.c
-    igraph/src/cs_tdfs.c
-    igraph/src/cs_transpose.c
-    igraph/src/cs_updown.c
-    igraph/src/cs_usolve.c
-    igraph/src/cs_util.c
-    igraph/src/cs_utsolve.c
-    igraph/src/ctype.c
-    igraph/src/d_abs.c
-    igraph/src/d_acos.c
-    igraph/src/d_asin.c
-    igraph/src/dasum.c
-    igraph/src/d_atan.c
-    igraph/src/d_atn2.c
-    igraph/src/daxpy.c
-    igraph/src/d_cnjg.c
-    igraph/src/dcopy.c
-    igraph/src/d_cos.c
-    igraph/src/d_cosh.c
-    igraph/src/d_dim.c
-    igraph/src/ddot.c
-    igraph/src/decomposition.c
-    igraph/src/derf_.c
-    igraph/src/derfc_.c
-    igraph/src/d_exp.c
-    igraph/src/dfe.c
-    igraph/src/dgebak.c
-    igraph/src/dgebal.c
-    igraph/src/dgeev.c
-    igraph/src/dgeevx.c
-    igraph/src/dgehd2.c
-    igraph/src/dgehrd.c
-    igraph/src/dgemm.c
-    igraph/src/dgemv.c
-    igraph/src/dgeqr2.c
-    igraph/src/dger.c
-    igraph/src/dgesv.c
-    igraph/src/dgetf2.c
-    igraph/src/dgetrf.c
-    igraph/src/dgetrs.c
-    igraph/src/dgetv0.c
-    igraph/src/dhseqr.c
-    igraph/src/d_imag.c
-    igraph/src/d_int.c
-    igraph/src/disnan.c
-    igraph/src/distances.c
-    igraph/src/dlabad.c
-    igraph/src/dlacn2.c
-    igraph/src/dlacpy.c
-    igraph/src/dladiv.c
-    igraph/src/dlae2.c
-    igraph/src/dlaebz.c
-    igraph/src/dlaev2.c
-    igraph/src/dlaexc.c
-    igraph/src/dlagtf.c
-    igraph/src/dlagts.c
-    igraph/src/dlahqr.c
-    igraph/src/dlahr2.c
-    igraph/src/dlaisnan.c
-    igraph/src/dlaln2.c
-    igraph/src/dlamch.c
-    igraph/src/dlaneg.c
-    igraph/src/dlange.c
-    igraph/src/dlanhs.c
-    igraph/src/dlanst.c
-    igraph/src/dlansy.c
-    igraph/src/dlanv2.c
-    igraph/src/dlapy2.c
-    igraph/src/dlaqr0.c
-    igraph/src/dlaqr1.c
-    igraph/src/dlaqr2.c
-    igraph/src/dlaqr3.c
-    igraph/src/dlaqr4.c
-    igraph/src/dlaqr5.c
-    igraph/src/dlaqrb.c
-    igraph/src/dlaqtr.c
-    igraph/src/dlar1v.c
-    igraph/src/dlarfb.c
-    igraph/src/dlarf.c
-    igraph/src/dlarfg.c
-    igraph/src/dlarft.c
-    igraph/src/dlarfx.c
-    igraph/src/dlarnv.c
-    igraph/src/dlarra.c
-    igraph/src/dlarrb.c
-    igraph/src/dlarrc.c
-    igraph/src/dlarrd.c
-    igraph/src/dlarre.c
-    igraph/src/dlarrf.c
-    igraph/src/dlarrj.c
-    igraph/src/dlarrk.c
-    igraph/src/dlarrr.c
-    igraph/src/dlarrv.c
-    igraph/src/dlartg.c
-    igraph/src/dlaruv.c
-    igraph/src/dlascl.c
-    igraph/src/dlaset.c
-    igraph/src/dlasq2.c
-    igraph/src/dlasq3.c
-    igraph/src/dlasq4.c
-    igraph/src/dlasq5.c
-    igraph/src/dlasq6.c
-    igraph/src/dlasr.c
-    igraph/src/dlasrt.c
-    igraph/src/dlassq.c
-    igraph/src/dlaswp.c
-    igraph/src/dlasy2.c
-    igraph/src/dlatrd.c
-    igraph/src/d_lg10.c
-    igraph/src/d_log.c
-    igraph/src/d_mod.c
-    igraph/src/dmout.c
-    igraph/src/dnaitr.c
-    igraph/src/dnapps.c
-    igraph/src/dnaup2.c
-    igraph/src/dnaupd.c
-    igraph/src/dnconv.c
-    igraph/src/dneigh.c
-    igraph/src/dneupd.c
-    igraph/src/dngets.c
-    igraph/src/d_nint.c
-    igraph/src/dnrm2.c
-    igraph/src/dolio.c
-    igraph/src/dorg2r.c
-    igraph/src/dorghr.c
-    igraph/src/dorgqr.c
-    igraph/src/dorm2l.c
-    igraph/src/dorm2r.c
-    igraph/src/dormhr.c
-    igraph/src/dormql.c
-    igraph/src/dormqr.c
-    igraph/src/dormtr.c
-    igraph/src/dotproduct.c
-    igraph/src/dpotf2.c
-    igraph/src/dpotrf.c
-    igraph/src/d_prod.c
-    igraph/src/dqueue.c
-    igraph/src/drot.c
-    igraph/src/dsaitr.c
-    igraph/src/dsapps.c
-    igraph/src/dsaup2.c
-    igraph/src/dsaupd.c
-    igraph/src/dscal.c
-    igraph/src/dsconv.c
-    igraph/src/dseigt.c
-    igraph/src/dsesrt.c
-    igraph/src/dseupd.c
-    igraph/src/dsgets.c
-    igraph/src/d_sign.c
-    igraph/src/d_sin.c
-    igraph/src/d_sinh.c
-    igraph/src/dsortc.c
-    igraph/src/dsortr.c
-    igraph/src/d_sqrt.c
-    igraph/src/dstatn.c
-    igraph/src/dstats.c
-    igraph/src/dstebz.c
-    igraph/src/dstein.c
-    igraph/src/dstemr.c
-    igraph/src/dsteqr.c
-    igraph/src/dsterf.c
-    igraph/src/dstqrb.c
-    igraph/src/dswap.c
-    igraph/src/dsyevr.c
-    igraph/src/dsymv.c
-    igraph/src/dsyr2.c
-    igraph/src/dsyr2k.c
-    igraph/src/dsyrk.c
-    igraph/src/dsytd2.c
-    igraph/src/dsytrd.c
-    igraph/src/d_tan.c
-    igraph/src/d_tanh.c
-    igraph/src/dtime_.c
-    igraph/src/dtrevc.c
-    igraph/src/dtrexc.c
-    igraph/src/dtrmm.c
-    igraph/src/dtrmv.c
-    igraph/src/dtrsen.c
-    igraph/src/dtrsm.c
-    igraph/src/dtrsna.c
-    igraph/src/dtrsv.c
-    igraph/src/dtrsyl.c
-    igraph/src/due.c
-    igraph/src/dummy.c
-    igraph/src/dvout.c
-    igraph/src/ef1asc_.c
-    igraph/src/ef1cmc_.c
-    igraph/src/eigen.c
-    igraph/src/embedding.c
-    igraph/src/endfile.c
-    igraph/src/erf_.c
-    igraph/src/erfc_.c
-    igraph/src/err.c
-    igraph/src/error.c
-    igraph/src/etime_.c
-    igraph/src/exit_.c
-    igraph/src/f77_aloc.c
-    igraph/src/f77vers.c
-    igraph/src/fast_community.c
-    igraph/src/feedback_arc_set.c
-    igraph/src/flow.c
-    igraph/src/fmt.c
-    igraph/src/fmtlib.c
-    igraph/src/foreign.c
-    igraph/src/foreign-dl-lexer.c
-    igraph/src/foreign-dl-parser.c
-    igraph/src/foreign-gml-lexer.c
-    igraph/src/foreign-gml-parser.c
-    igraph/src/foreign-graphml.c
-    igraph/src/foreign-lgl-lexer.c
-    igraph/src/foreign-lgl-parser.c
-    igraph/src/foreign-ncol-lexer.c
-    igraph/src/foreign-ncol-parser.c
-    igraph/src/foreign-pajek-lexer.c
-    igraph/src/foreign-pajek-parser.c
-    igraph/src/forestfire.c
-    igraph/src/fortran_intrinsics.c
-    igraph/src/ftell_.c
-    igraph/src/games.c
-    igraph/src/getenv_.c
-    igraph/src/glet.c
-    igraph/src/glpk_support.c
-    igraph/src/gml_tree.c
-    igraph/src/gss.c
-    igraph/src/h_abs.c
-    igraph/src/hacks.c
-    igraph/src/h_dim.c
-    igraph/src/h_dnnt.c
-    igraph/src/heap.c
-    igraph/src/h_indx.c
-    igraph/src/h_len.c
-    igraph/src/hl_ge.c
-    igraph/src/hl_gt.c
-    igraph/src/hl_le.c
-    igraph/src/hl_lt.c
-    igraph/src/h_mod.c
-    igraph/src/h_nint.c
-    igraph/src/h_sign.c
-    igraph/src/i77vers.c
-    igraph/src/i_abs.c
-    igraph/src/idamax.c
-    igraph/src/i_dim.c
-    igraph/src/i_dnnt.c
-    igraph/src/ieeeck.c
-    igraph/src/igraph_buckets.c
-    igraph/src/igraph_cliquer.c
-    igraph/src/igraph_error.c
-    igraph/src/igraph_estack.c
-    igraph/src/igraph_fixed_vectorlist.c
-    igraph/src/igraph_grid.c
-    igraph/src/igraph_hashtable.c
-    igraph/src/igraph_heap.c
-    igraph/src/igraph_marked_queue.c
-    igraph/src/igraph_psumtree.c
-    igraph/src/igraph_set.c
-    igraph/src/igraph_stack.c
-    igraph/src/igraph_strvector.c
-    igraph/src/igraph_trie.c
-    igraph/src/i_indx.c
-    igraph/src/iio.c
-    igraph/src/iladlc.c
-    igraph/src/iladlr.c
-    igraph/src/ilaenv.c
-    igraph/src/i_len.c
-    igraph/src/ilnw.c
-    igraph/src/i_mod.c
-    igraph/src/i_nint.c
-    igraph/src/inquire.c
-    igraph/src/interrupt.c
-    igraph/src/iparmq.c
-    igraph/src/i_sign.c
-    igraph/src/iterators.c
-    igraph/src/ivout.c
-    igraph/src/kolmogorov.c
-    igraph/src/lad.c
-    igraph/src/lapack.c
-    igraph/src/layout.c
-    igraph/src/layout_dh.c
-    igraph/src/layout_fr.c
-    igraph/src/layout_gem.c
-    igraph/src/layout_kk.c
-    igraph/src/lbfgs.c
-    igraph/src/lbitbits.c
-    igraph/src/lbitshft.c
-    igraph/src/len_trim.c
-    igraph/src/l_ge.c
-    igraph/src/l_gt.c
-    igraph/src/l_le.c
-    igraph/src/l_lt.c
-    igraph/src/lread.c
-    igraph/src/lsame.c
-    igraph/src/lsap.c
-    igraph/src/lwrite.c
-    igraph/src/matching.c
-    igraph/src/math.c
-    igraph/src/matrix.c
-    igraph/src/maximal_cliques.c
-    igraph/src/memory.c
-    igraph/src/microscopic_update.c
-    igraph/src/mixing.c
-    igraph/src/motifs.c
-    igraph/src/open.c
-    igraph/src/operators.c
-    igraph/src/optimal_modularity.c
-    igraph/src/options.c
-    igraph/src/other.c
-    igraph/src/paths.c
-    igraph/src/plfit.c
-    igraph/src/pow_ci.c
-    igraph/src/pow_dd.c
-    igraph/src/pow_di.c
-    igraph/src/pow_hh.c
-    igraph/src/pow_ii.c
-    igraph/src/pow_ri.c
-    igraph/src/pow_zi.c
-    igraph/src/pow_zz.c
-    igraph/src/progress.c
-    igraph/src/qsort.c
-    igraph/src/qsort_r.c
-    igraph/src/r_abs.c
-    igraph/src/r_acos.c
-    igraph/src/random.c
-    igraph/src/random_walk.c
-    igraph/src/r_asin.c
-    igraph/src/r_atan.c
-    igraph/src/r_atn2.c
-    igraph/src/r_cnjg.c
-    igraph/src/r_cos.c
-    igraph/src/r_cosh.c
-    igraph/src/rdfmt.c
-    igraph/src/r_dim.c
-    igraph/src/reorder.c
-    igraph/src/rewind.c
-    igraph/src/r_exp.c
-    igraph/src/r_imag.c
-    igraph/src/r_int.c
-    igraph/src/r_lg10.c
-    igraph/src/r_log.c
-    igraph/src/r_mod.c
-    igraph/src/r_nint.c
-    igraph/src/rsfe.c
-    igraph/src/r_sign.c
-    igraph/src/r_sin.c
-    igraph/src/r_sinh.c
-    igraph/src/rsli.c
-    igraph/src/rsne.c
-    igraph/src/r_sqrt.c
-    igraph/src/r_tan.c
-    igraph/src/r_tanh.c
-    igraph/src/sbm.c
-    igraph/src/scan.c
-    igraph/src/s_cat.c
-    igraph/src/scg_approximate_methods.c
-    igraph/src/scg.c
-    igraph/src/scg_exact_scg.c
-    igraph/src/scg_kmeans.c
-    igraph/src/scg_optimal_method.c
-    igraph/src/scg_utils.c
-    igraph/src/s_cmp.c
-    igraph/src/s_copy.c
-    igraph/src/second.c
-    igraph/src/separators.c
-    igraph/src/sfe.c
-    igraph/src/sig_die.c
-    igraph/src/signal_.c
-    igraph/src/signbit.c
-    igraph/src/sir.c
-    igraph/src/spanning_trees.c
-    igraph/src/sparsemat.c
-    igraph/src/s_paus.c
-    igraph/src/spectral_properties.c
-    igraph/src/spmatrix.c
-    igraph/src/s_rnge.c
-    igraph/src/s_stop.c
-    igraph/src/statusbar.c
-    igraph/src/st-cuts.c
-    igraph/src/structural_properties.c
-    igraph/src/structure_generators.c
-    igraph/src/sue.c
-    igraph/src/sugiyama.c
-    igraph/src/system_.c
-    igraph/src/topology.c
-    igraph/src/triangles.c
-    igraph/src/type_indexededgelist.c
-    igraph/src/types.c
-    igraph/src/typesize.c
-    igraph/src/uio.c
-    igraph/src/uninit.c
-    igraph/src/util.c
-    igraph/src/vector.c
-    igraph/src/vector_ptr.c
-    igraph/src/version.c
-    igraph/src/visitors.c
-    igraph/src/wref.c
-    igraph/src/wrtfmt.c
-    igraph/src/wsfe.c
-    igraph/src/wsle.c
-    igraph/src/wsne.c
-    igraph/src/xerbla.c
-    igraph/src/xwsne.c
-    igraph/src/z_abs.c
-    igraph/src/z_cos.c
-    igraph/src/z_div.c
-    igraph/src/zeroin.c
-    igraph/src/zeta.c
-    igraph/src/z_exp.c
-    igraph/src/z_log.c
-    igraph/src/z_sin.c
-    igraph/src/z_sqrt.c
-
-  cxx-sources:
-    igraph/src/clustertool.cpp
-    igraph/src/degree_sequence.cpp
-    igraph/src/DensityGrid_3d.cpp
-    igraph/src/DensityGrid.cpp
-    igraph/src/drl_graph_3d.cpp
-    igraph/src/drl_graph.cpp
-    igraph/src/drl_layout_3d.cpp
-    igraph/src/drl_layout.cpp
-    igraph/src/drl_parse.cpp
-    igraph/src/gengraph_box_list.cpp
-    igraph/src/gengraph_degree_sequence.cpp
-    igraph/src/gengraph_graph_molloy_hash.cpp
-    igraph/src/gengraph_graph_molloy_optimized.cpp
-    igraph/src/gengraph_mr-connected.cpp
-    igraph/src/gengraph_powerlaw.cpp
-    igraph/src/gengraph_random.cpp
-    igraph/src/NetDataTypes.cpp
-    igraph/src/NetRoutines.cpp
-    igraph/src/pottsmodel_2.cpp
-    igraph/src/prpack_base_graph.cpp
-    igraph/src/prpack.cpp
-    igraph/src/prpack_igraph_graph.cpp
-    igraph/src/prpack_preprocessed_ge_graph.cpp
-    igraph/src/prpack_preprocessed_gs_graph.cpp
-    igraph/src/prpack_preprocessed_scc_graph.cpp
-    igraph/src/prpack_preprocessed_schur_graph.cpp
-    igraph/src/prpack_result.cpp
-    igraph/src/prpack_solver.cpp
-    igraph/src/prpack_utils.cpp
-    igraph/src/walktrap_communities.cpp
-    igraph/src/walktrap.cpp
-    igraph/src/walktrap_graph.cpp
-    igraph/src/walktrap_heap.cpp
-    igraph/src/bliss.cc
-    igraph/src/bliss_heap.cc
-    igraph/src/defs.cc
-    igraph/src/graph.cc
-    igraph/src/igraph_hrg.cc
-    igraph/src/igraph_hrg_types.cc
-    igraph/src/infomap.cc
-    igraph/src/infomap_FlowGraph.cc
-    igraph/src/infomap_Greedy.cc
-    igraph/src/infomap_Node.cc
-    igraph/src/orbit.cc
-    igraph/src/partition.cc
-    igraph/src/uintseqhash.cc
-    igraph/src/utils.cc
-
-  include-dirs:
-    include
-    igraph/include
-    igraph/include/f2c
-    igraph/include/prpack
-    igraph/include/cs
-    igraph/include/cliquer
-    igraph/include/bliss
-    igraph/include/plfit
-  
-  cxx-options: -DPRPACK_IGRAPH_SUPPORT
-
-test-suite tests
-  type: exitcode-stdio-1.0
-  hs-source-dirs: tests
-  ghc-options:         -Wall
-  main-is: test.hs
-  other-modules:
-    Test.Basic
-    Test.Attributes
-    Test.Algorithms
-    Test.Utils
-
-  default-language:    Haskell2010
-  build-depends:
-      base
-    , haskell-igraph
-    , cereal
-    , conduit >= 1.3.0
-    , data-ordlist
-    , matrices
-    , tasty
-    , tasty-golden
-    , tasty-hunit
-    , random
-
-source-repository  head
-  type: git
-  location: https://github.com/kaizhang/haskell-igraph.git
-
+cabal-version: 2.2
+
+-- This file has been generated from package.yaml by hpack version 0.33.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: eec35679c2bc2e9790d121f0e5e57bf25eb87dcf0776ae132bba4f4ff0d168b1
+
+name:           haskell-igraph
+version:        0.8.5
+synopsis:       Bindings to the igraph C library (v0.8.5).
+description:    igraph<"http://igraph.org/c/"> is a library for creating and manipulating large graphs. This package provides the Haskell interface of igraph.
+category:       Math
+homepage:       https://github.com/jmazon/haskell-igraph#readme
+bug-reports:    https://github.com/jmazon/haskell-igraph/issues
+author:         Kai Zhang
+maintainer:     Jean-Baptiste Mazon
+copyright:      (c) 2016-2021 Kai Zhang
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    cbits/bytestring.h
+    cbits/haskell_attributes.h
+    cbits/haskell_igraph.h
+    igraph/include/arith.h
+    igraph/include/atlas-edges.h
+    igraph/include/bigint.h
+    igraph/include/bignum.h
+    igraph/include/config.h
+    igraph/include/DensityGrid.h
+    igraph/include/DensityGrid_3d.h
+    igraph/include/drl_graph.h
+    igraph/include/drl_graph_3d.h
+    igraph/include/drl_layout.h
+    igraph/include/drl_layout_3d.h
+    igraph/include/drl_Node.h
+    igraph/include/drl_Node_3d.h
+    igraph/include/drl_parse.h
+    igraph/include/f2c.h
+    igraph/include/foreign-dl-header.h
+    igraph/include/foreign-dl-parser.h
+    igraph/include/foreign-gml-header.h
+    igraph/include/foreign-gml-parser.h
+    igraph/include/foreign-lgl-header.h
+    igraph/include/foreign-lgl-parser.h
+    igraph/include/foreign-ncol-header.h
+    igraph/include/foreign-ncol-parser.h
+    igraph/include/foreign-pajek-header.h
+    igraph/include/foreign-pajek-parser.h
+    igraph/include/gengraph_box_list.h
+    igraph/include/gengraph_definitions.h
+    igraph/include/gengraph_degree_sequence.h
+    igraph/include/gengraph_graph_molloy_hash.h
+    igraph/include/gengraph_graph_molloy_optimized.h
+    igraph/include/gengraph_hash.h
+    igraph/include/gengraph_header.h
+    igraph/include/gengraph_powerlaw.h
+    igraph/include/gengraph_qsort.h
+    igraph/include/gengraph_random.h
+    igraph/include/gengraph_vertex_cover.h
+    igraph/include/hrg_dendro.h
+    igraph/include/hrg_graph.h
+    igraph/include/hrg_graph_simp.h
+    igraph/include/hrg_rbtree.h
+    igraph/include/hrg_splittree_eq.h
+    igraph/include/igraph.h
+    igraph/include/igraph_adjlist.h
+    igraph/include/igraph_arpack.h
+    igraph/include/igraph_arpack_internal.h
+    igraph/include/igraph_array.h
+    igraph/include/igraph_array_pmt.h
+    igraph/include/igraph_attributes.h
+    igraph/include/igraph_bipartite.h
+    igraph/include/igraph_blas.h
+    igraph/include/igraph_blas_internal.h
+    igraph/include/igraph_centrality.h
+    igraph/include/igraph_cliquer.h
+    igraph/include/igraph_cliques.h
+    igraph/include/igraph_cocitation.h
+    igraph/include/igraph_cohesive_blocks.h
+    igraph/include/igraph_coloring.h
+    igraph/include/igraph_community.h
+    igraph/include/igraph_complex.h
+    igraph/include/igraph_components.h
+    igraph/include/igraph_constants.h
+    igraph/include/igraph_constructors.h
+    igraph/include/igraph_conversion.h
+    igraph/include/igraph_datatype.h
+    igraph/include/igraph_decls.h
+    igraph/include/igraph_dqueue.h
+    igraph/include/igraph_dqueue_pmt.h
+    igraph/include/igraph_eigen.h
+    igraph/include/igraph_embedding.h
+    igraph/include/igraph_epidemics.h
+    igraph/include/igraph_error.h
+    igraph/include/igraph_estack.h
+    igraph/include/igraph_flow.h
+    igraph/include/igraph_flow_internal.h
+    igraph/include/igraph_foreign.h
+    igraph/include/igraph_games.h
+    igraph/include/igraph_glpk_support.h
+    igraph/include/igraph_gml_tree.h
+    igraph/include/igraph_graphlets.h
+    igraph/include/igraph_hacks_internal.h
+    igraph/include/igraph_handle_exceptions.h
+    igraph/include/igraph_heap.h
+    igraph/include/igraph_heap_pmt.h
+    igraph/include/igraph_hrg.h
+    igraph/include/igraph_interface.h
+    igraph/include/igraph_interrupt.h
+    igraph/include/igraph_interrupt_internal.h
+    igraph/include/igraph_isoclasses.h
+    igraph/include/igraph_iterators.h
+    igraph/include/igraph_lapack.h
+    igraph/include/igraph_lapack_internal.h
+    igraph/include/igraph_layout.h
+    igraph/include/igraph_lsap.h
+    igraph/include/igraph_marked_queue.h
+    igraph/include/igraph_matching.h
+    igraph/include/igraph_math.h
+    igraph/include/igraph_matrix.h
+    igraph/include/igraph_matrix_pmt.h
+    igraph/include/igraph_memory.h
+    igraph/include/igraph_microscopic_update.h
+    igraph/include/igraph_mixing.h
+    igraph/include/igraph_motifs.h
+    igraph/include/igraph_neighborhood.h
+    igraph/include/igraph_nongraph.h
+    igraph/include/igraph_operators.h
+    igraph/include/igraph_paths.h
+    igraph/include/igraph_pmt.h
+    igraph/include/igraph_pmt_off.h
+    igraph/include/igraph_progress.h
+    igraph/include/igraph_psumtree.h
+    igraph/include/igraph_qsort.h
+    igraph/include/igraph_random.h
+    igraph/include/igraph_scan.h
+    igraph/include/igraph_scg.h
+    igraph/include/igraph_separators.h
+    igraph/include/igraph_sparsemat.h
+    igraph/include/igraph_spmatrix.h
+    igraph/include/igraph_stack.h
+    igraph/include/igraph_stack_pmt.h
+    igraph/include/igraph_statusbar.h
+    igraph/include/igraph_structural.h
+    igraph/include/igraph_strvector.h
+    igraph/include/igraph_threading.h
+    igraph/include/igraph_topology.h
+    igraph/include/igraph_transitivity.h
+    igraph/include/igraph_types.h
+    igraph/include/igraph_types_internal.h
+    igraph/include/igraph_vector.h
+    igraph/include/igraph_vector_pmt.h
+    igraph/include/igraph_vector_ptr.h
+    igraph/include/igraph_vector_type.h
+    igraph/include/igraph_version.h
+    igraph/include/igraph_visitor.h
+    igraph/include/infomap_FlowGraph.h
+    igraph/include/infomap_Greedy.h
+    igraph/include/infomap_Node.h
+    igraph/include/maximal_cliques_template.h
+    igraph/include/NetDataTypes.h
+    igraph/include/NetRoutines.h
+    igraph/include/pottsmodel_2.h
+    igraph/include/prpack.h
+    igraph/include/scg_headers.h
+    igraph/include/structural_properties_internal.h
+    igraph/include/triangles_template.h
+    igraph/include/triangles_template1.h
+    igraph/include/walktrap_communities.h
+    igraph/include/walktrap_graph.h
+    igraph/include/walktrap_heap.h
+    igraph/include/array.pmt
+    igraph/include/dqueue.pmt
+    igraph/include/heap.pmt
+    igraph/include/matrix.pmt
+    igraph/include/stack.pmt
+    igraph/include/vector.pmt
+    igraph/include/f2c/fio.h
+    igraph/include/f2c/fmt.h
+    igraph/include/f2c/fp.h
+    igraph/include/f2c/lio.h
+    igraph/include/f2c/signal1.h
+    igraph/include/f2c/sysdep1.h
+    igraph/include/prpack/prpack.h
+    igraph/include/prpack/prpack_base_graph.h
+    igraph/include/prpack/prpack_csc.h
+    igraph/include/prpack/prpack_csr.h
+    igraph/include/prpack/prpack_edge_list.h
+    igraph/include/prpack/prpack_igraph_graph.h
+    igraph/include/prpack/prpack_preprocessed_ge_graph.h
+    igraph/include/prpack/prpack_preprocessed_graph.h
+    igraph/include/prpack/prpack_preprocessed_gs_graph.h
+    igraph/include/prpack/prpack_preprocessed_scc_graph.h
+    igraph/include/prpack/prpack_preprocessed_schur_graph.h
+    igraph/include/prpack/prpack_result.h
+    igraph/include/prpack/prpack_solver.h
+    igraph/include/prpack/prpack_utils.h
+    igraph/include/cs/cs.h
+    igraph/include/cs/UFconfig.h
+    igraph/include/cliquer/cliquer.h
+    igraph/include/cliquer/cliquerconf.h
+    igraph/include/cliquer/graph.h
+    igraph/include/cliquer/misc.h
+    igraph/include/cliquer/reorder.h
+    igraph/include/cliquer/set.h
+    igraph/include/bliss/bignum.hh
+    igraph/include/bliss/defs.hh
+    igraph/include/bliss/graph.hh
+    igraph/include/bliss/heap.hh
+    igraph/include/bliss/kqueue.hh
+    igraph/include/bliss/kstack.hh
+    igraph/include/bliss/orbit.hh
+    igraph/include/bliss/partition.hh
+    igraph/include/bliss/uintseqhash.hh
+    igraph/include/bliss/utils.hh
+    igraph/include/plfit/arithmetic_ansi.h
+    igraph/include/plfit/arithmetic_sse_double.h
+    igraph/include/plfit/arithmetic_sse_float.h
+    igraph/include/plfit/error.h
+    igraph/include/plfit/gss.h
+    igraph/include/plfit/hzeta.h
+    igraph/include/plfit/kolmogorov.h
+    igraph/include/plfit/lbfgs.h
+    igraph/include/plfit/mt.h
+    igraph/include/plfit/platform.h
+    igraph/include/plfit/plfit.h
+    igraph/include/plfit/sampling.h
+    igraph/AUTHORS
+    igraph/COPYING
+    stack.yaml
+
+extra-doc-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://github.com/jmazon/haskell-igraph
+
+library
+  exposed-modules:
+      IGraph.Internal.Initialization
+      IGraph.Internal.Constants
+      IGraph.Internal
+      IGraph
+      IGraph.Mutable
+      IGraph.Random
+      IGraph.Types
+      IGraph.Algorithms
+      IGraph.Algorithms.Structure
+      IGraph.Algorithms.Community
+      IGraph.Algorithms.Clique
+      IGraph.Algorithms.Layout
+      IGraph.Algorithms.Motif
+      IGraph.Algorithms.Generators
+      IGraph.Algorithms.Isomorphism
+      IGraph.Algorithms.Centrality
+  other-modules:
+      IGraph.Internal.C2HS
+  hs-source-dirs:
+      src
+  ghc-options: -Wall -fno-warn-unused-matches
+  cxx-options: -std=c++11 -DPRPACK_IGRAPH_SUPPORT
+  include-dirs:
+      cbits
+      igraph/include
+      igraph/include/f2c
+      igraph/include/prpack
+      igraph/include/cs
+      igraph/include/cliquer
+      igraph/include/bliss
+      igraph/include/plfit
+  c-sources:
+      cbits/bytestring.c
+      cbits/haskell_attributes.c
+      cbits/haskell_igraph.c
+      igraph/src/abort_.c
+      igraph/src/adjlist.c
+      igraph/src/arithchk.c
+      igraph/src/arpack.c
+      igraph/src/array.c
+      igraph/src/atlas.c
+      igraph/src/attributes.c
+      igraph/src/backspac.c
+      igraph/src/basic_query.c
+      igraph/src/bfgs.c
+      igraph/src/bigint.c
+      igraph/src/bignum.c
+      igraph/src/bipartite.c
+      igraph/src/blas.c
+      igraph/src/c_abs.c
+      igraph/src/c_cos.c
+      igraph/src/c_div.c
+      igraph/src/c_exp.c
+      igraph/src/c_log.c
+      igraph/src/c_sin.c
+      igraph/src/c_sqrt.c
+      igraph/src/cabs.c
+      igraph/src/cattributes.c
+      igraph/src/centrality.c
+      igraph/src/cliquer.c
+      igraph/src/cliquer_graph.c
+      igraph/src/cliques.c
+      igraph/src/close.c
+      igraph/src/cocitation.c
+      igraph/src/cohesive_blocks.c
+      igraph/src/coloring.c
+      igraph/src/community.c
+      igraph/src/community_leiden.c
+      igraph/src/complex.c
+      igraph/src/components.c
+      igraph/src/conversion.c
+      igraph/src/cores.c
+      igraph/src/cs_add.c
+      igraph/src/cs_amd.c
+      igraph/src/cs_chol.c
+      igraph/src/cs_cholsol.c
+      igraph/src/cs_compress.c
+      igraph/src/cs_counts.c
+      igraph/src/cs_cumsum.c
+      igraph/src/cs_dfs.c
+      igraph/src/cs_dmperm.c
+      igraph/src/cs_droptol.c
+      igraph/src/cs_dropzeros.c
+      igraph/src/cs_dupl.c
+      igraph/src/cs_entry.c
+      igraph/src/cs_ereach.c
+      igraph/src/cs_etree.c
+      igraph/src/cs_fkeep.c
+      igraph/src/cs_gaxpy.c
+      igraph/src/cs_happly.c
+      igraph/src/cs_house.c
+      igraph/src/cs_ipvec.c
+      igraph/src/cs_leaf.c
+      igraph/src/cs_load.c
+      igraph/src/cs_lsolve.c
+      igraph/src/cs_ltsolve.c
+      igraph/src/cs_lu.c
+      igraph/src/cs_lusol.c
+      igraph/src/cs_malloc.c
+      igraph/src/cs_maxtrans.c
+      igraph/src/cs_multiply.c
+      igraph/src/cs_norm.c
+      igraph/src/cs_permute.c
+      igraph/src/cs_pinv.c
+      igraph/src/cs_post.c
+      igraph/src/cs_print.c
+      igraph/src/cs_pvec.c
+      igraph/src/cs_qr.c
+      igraph/src/cs_qrsol.c
+      igraph/src/cs_randperm.c
+      igraph/src/cs_reach.c
+      igraph/src/cs_scatter.c
+      igraph/src/cs_scc.c
+      igraph/src/cs_schol.c
+      igraph/src/cs_spsolve.c
+      igraph/src/cs_sqr.c
+      igraph/src/cs_symperm.c
+      igraph/src/cs_tdfs.c
+      igraph/src/cs_transpose.c
+      igraph/src/cs_updown.c
+      igraph/src/cs_usolve.c
+      igraph/src/cs_util.c
+      igraph/src/cs_utsolve.c
+      igraph/src/ctype.c
+      igraph/src/d_abs.c
+      igraph/src/d_acos.c
+      igraph/src/d_asin.c
+      igraph/src/d_atan.c
+      igraph/src/d_atn2.c
+      igraph/src/d_cnjg.c
+      igraph/src/d_cos.c
+      igraph/src/d_cosh.c
+      igraph/src/d_dim.c
+      igraph/src/d_exp.c
+      igraph/src/d_imag.c
+      igraph/src/d_int.c
+      igraph/src/d_lg10.c
+      igraph/src/d_log.c
+      igraph/src/d_mod.c
+      igraph/src/d_nint.c
+      igraph/src/d_prod.c
+      igraph/src/d_sign.c
+      igraph/src/d_sin.c
+      igraph/src/d_sinh.c
+      igraph/src/d_sqrt.c
+      igraph/src/d_tan.c
+      igraph/src/d_tanh.c
+      igraph/src/dasum.c
+      igraph/src/daxpy.c
+      igraph/src/dcopy.c
+      igraph/src/ddot.c
+      igraph/src/decomposition.c
+      igraph/src/derf_.c
+      igraph/src/derfc_.c
+      igraph/src/dfe.c
+      igraph/src/dgebak.c
+      igraph/src/dgebal.c
+      igraph/src/dgeev.c
+      igraph/src/dgeevx.c
+      igraph/src/dgehd2.c
+      igraph/src/dgehrd.c
+      igraph/src/dgemm.c
+      igraph/src/dgemv.c
+      igraph/src/dgeqr2.c
+      igraph/src/dger.c
+      igraph/src/dgesv.c
+      igraph/src/dgetf2.c
+      igraph/src/dgetrf.c
+      igraph/src/dgetrs.c
+      igraph/src/dgetv0.c
+      igraph/src/dhseqr.c
+      igraph/src/disnan.c
+      igraph/src/distances.c
+      igraph/src/dlabad.c
+      igraph/src/dlacn2.c
+      igraph/src/dlacpy.c
+      igraph/src/dladiv.c
+      igraph/src/dlae2.c
+      igraph/src/dlaebz.c
+      igraph/src/dlaev2.c
+      igraph/src/dlaexc.c
+      igraph/src/dlagtf.c
+      igraph/src/dlagts.c
+      igraph/src/dlahqr.c
+      igraph/src/dlahr2.c
+      igraph/src/dlaisnan.c
+      igraph/src/dlaln2.c
+      igraph/src/dlamch.c
+      igraph/src/dlaneg.c
+      igraph/src/dlange.c
+      igraph/src/dlanhs.c
+      igraph/src/dlanst.c
+      igraph/src/dlansy.c
+      igraph/src/dlanv2.c
+      igraph/src/dlapy2.c
+      igraph/src/dlaqr0.c
+      igraph/src/dlaqr1.c
+      igraph/src/dlaqr2.c
+      igraph/src/dlaqr3.c
+      igraph/src/dlaqr4.c
+      igraph/src/dlaqr5.c
+      igraph/src/dlaqrb.c
+      igraph/src/dlaqtr.c
+      igraph/src/dlar1v.c
+      igraph/src/dlarf.c
+      igraph/src/dlarfb.c
+      igraph/src/dlarfg.c
+      igraph/src/dlarft.c
+      igraph/src/dlarfx.c
+      igraph/src/dlarnv.c
+      igraph/src/dlarra.c
+      igraph/src/dlarrb.c
+      igraph/src/dlarrc.c
+      igraph/src/dlarrd.c
+      igraph/src/dlarre.c
+      igraph/src/dlarrf.c
+      igraph/src/dlarrj.c
+      igraph/src/dlarrk.c
+      igraph/src/dlarrr.c
+      igraph/src/dlarrv.c
+      igraph/src/dlartg.c
+      igraph/src/dlaruv.c
+      igraph/src/dlascl.c
+      igraph/src/dlaset.c
+      igraph/src/dlasq2.c
+      igraph/src/dlasq3.c
+      igraph/src/dlasq4.c
+      igraph/src/dlasq5.c
+      igraph/src/dlasq6.c
+      igraph/src/dlasr.c
+      igraph/src/dlasrt.c
+      igraph/src/dlassq.c
+      igraph/src/dlaswp.c
+      igraph/src/dlasy2.c
+      igraph/src/dlatrd.c
+      igraph/src/dmout.c
+      igraph/src/dnaitr.c
+      igraph/src/dnapps.c
+      igraph/src/dnaup2.c
+      igraph/src/dnaupd.c
+      igraph/src/dnconv.c
+      igraph/src/dneigh.c
+      igraph/src/dneupd.c
+      igraph/src/dngets.c
+      igraph/src/dnrm2.c
+      igraph/src/dolio.c
+      igraph/src/dorg2r.c
+      igraph/src/dorghr.c
+      igraph/src/dorgqr.c
+      igraph/src/dorm2l.c
+      igraph/src/dorm2r.c
+      igraph/src/dormhr.c
+      igraph/src/dormql.c
+      igraph/src/dormqr.c
+      igraph/src/dormtr.c
+      igraph/src/dotproduct.c
+      igraph/src/dpotf2.c
+      igraph/src/dpotrf.c
+      igraph/src/dqueue.c
+      igraph/src/drot.c
+      igraph/src/dsaitr.c
+      igraph/src/dsapps.c
+      igraph/src/dsaup2.c
+      igraph/src/dsaupd.c
+      igraph/src/dscal.c
+      igraph/src/dsconv.c
+      igraph/src/dseigt.c
+      igraph/src/dsesrt.c
+      igraph/src/dseupd.c
+      igraph/src/dsgets.c
+      igraph/src/dsortc.c
+      igraph/src/dsortr.c
+      igraph/src/dstatn.c
+      igraph/src/dstats.c
+      igraph/src/dstebz.c
+      igraph/src/dstein.c
+      igraph/src/dstemr.c
+      igraph/src/dsteqr.c
+      igraph/src/dsterf.c
+      igraph/src/dstqrb.c
+      igraph/src/dswap.c
+      igraph/src/dsyevr.c
+      igraph/src/dsymv.c
+      igraph/src/dsyr2.c
+      igraph/src/dsyr2k.c
+      igraph/src/dsyrk.c
+      igraph/src/dsytd2.c
+      igraph/src/dsytrd.c
+      igraph/src/dtime_.c
+      igraph/src/dtrevc.c
+      igraph/src/dtrexc.c
+      igraph/src/dtrmm.c
+      igraph/src/dtrmv.c
+      igraph/src/dtrsen.c
+      igraph/src/dtrsm.c
+      igraph/src/dtrsna.c
+      igraph/src/dtrsv.c
+      igraph/src/dtrsyl.c
+      igraph/src/due.c
+      igraph/src/dummy.c
+      igraph/src/dvout.c
+      igraph/src/ef1asc_.c
+      igraph/src/ef1cmc_.c
+      igraph/src/eigen.c
+      igraph/src/embedding.c
+      igraph/src/endfile.c
+      igraph/src/erf_.c
+      igraph/src/erfc_.c
+      igraph/src/err.c
+      igraph/src/error.c
+      igraph/src/etime_.c
+      igraph/src/exit_.c
+      igraph/src/f77_aloc.c
+      igraph/src/f77vers.c
+      igraph/src/fast_community.c
+      igraph/src/feedback_arc_set.c
+      igraph/src/flow.c
+      igraph/src/fmt.c
+      igraph/src/fmtlib.c
+      igraph/src/foreign-dl-lexer.c
+      igraph/src/foreign-dl-parser.c
+      igraph/src/foreign-gml-lexer.c
+      igraph/src/foreign-gml-parser.c
+      igraph/src/foreign-graphml.c
+      igraph/src/foreign-lgl-lexer.c
+      igraph/src/foreign-lgl-parser.c
+      igraph/src/foreign-ncol-lexer.c
+      igraph/src/foreign-ncol-parser.c
+      igraph/src/foreign-pajek-lexer.c
+      igraph/src/foreign-pajek-parser.c
+      igraph/src/foreign.c
+      igraph/src/forestfire.c
+      igraph/src/fortran_intrinsics.c
+      igraph/src/ftell_.c
+      igraph/src/games.c
+      igraph/src/getenv_.c
+      igraph/src/glet.c
+      igraph/src/glpk_support.c
+      igraph/src/gml_tree.c
+      igraph/src/gss.c
+      igraph/src/h_abs.c
+      igraph/src/h_dim.c
+      igraph/src/h_dnnt.c
+      igraph/src/h_indx.c
+      igraph/src/h_len.c
+      igraph/src/h_mod.c
+      igraph/src/h_nint.c
+      igraph/src/h_sign.c
+      igraph/src/hacks.c
+      igraph/src/heap.c
+      igraph/src/hl_ge.c
+      igraph/src/hl_gt.c
+      igraph/src/hl_le.c
+      igraph/src/hl_lt.c
+      igraph/src/hzeta.c
+      igraph/src/i77vers.c
+      igraph/src/i_abs.c
+      igraph/src/i_dim.c
+      igraph/src/i_dnnt.c
+      igraph/src/i_indx.c
+      igraph/src/i_len.c
+      igraph/src/i_mod.c
+      igraph/src/i_nint.c
+      igraph/src/i_sign.c
+      igraph/src/idamax.c
+      igraph/src/ieeeck.c
+      igraph/src/igraph_buckets.c
+      igraph/src/igraph_cliquer.c
+      igraph/src/igraph_error.c
+      igraph/src/igraph_estack.c
+      igraph/src/igraph_fixed_vectorlist.c
+      igraph/src/igraph_grid.c
+      igraph/src/igraph_hashtable.c
+      igraph/src/igraph_heap.c
+      igraph/src/igraph_marked_queue.c
+      igraph/src/igraph_psumtree.c
+      igraph/src/igraph_set.c
+      igraph/src/igraph_stack.c
+      igraph/src/igraph_strvector.c
+      igraph/src/igraph_trie.c
+      igraph/src/iio.c
+      igraph/src/iladlc.c
+      igraph/src/iladlr.c
+      igraph/src/ilaenv.c
+      igraph/src/ilnw.c
+      igraph/src/inquire.c
+      igraph/src/interrupt.c
+      igraph/src/iparmq.c
+      igraph/src/iterators.c
+      igraph/src/ivout.c
+      igraph/src/kolmogorov.c
+      igraph/src/l_ge.c
+      igraph/src/l_gt.c
+      igraph/src/l_le.c
+      igraph/src/l_lt.c
+      igraph/src/lad.c
+      igraph/src/lapack.c
+      igraph/src/layout.c
+      igraph/src/layout_dh.c
+      igraph/src/layout_fr.c
+      igraph/src/layout_gem.c
+      igraph/src/layout_kk.c
+      igraph/src/lbfgs.c
+      igraph/src/lbitbits.c
+      igraph/src/lbitshft.c
+      igraph/src/len_trim.c
+      igraph/src/lread.c
+      igraph/src/lsame.c
+      igraph/src/lsap.c
+      igraph/src/lwrite.c
+      igraph/src/matching.c
+      igraph/src/math.c
+      igraph/src/matrix.c
+      igraph/src/maximal_cliques.c
+      igraph/src/memory.c
+      igraph/src/microscopic_update.c
+      igraph/src/mixing.c
+      igraph/src/motifs.c
+      igraph/src/mt.c
+      igraph/src/open.c
+      igraph/src/operators.c
+      igraph/src/optimal_modularity.c
+      igraph/src/options.c
+      igraph/src/other.c
+      igraph/src/paths.c
+      igraph/src/platform.c
+      igraph/src/plfit.c
+      igraph/src/pow_ci.c
+      igraph/src/pow_dd.c
+      igraph/src/pow_di.c
+      igraph/src/pow_hh.c
+      igraph/src/pow_ii.c
+      igraph/src/pow_ri.c
+      igraph/src/pow_zi.c
+      igraph/src/pow_zz.c
+      igraph/src/progress.c
+      igraph/src/qsort.c
+      igraph/src/qsort_r.c
+      igraph/src/r_abs.c
+      igraph/src/r_acos.c
+      igraph/src/r_asin.c
+      igraph/src/r_atan.c
+      igraph/src/r_atn2.c
+      igraph/src/r_cnjg.c
+      igraph/src/r_cos.c
+      igraph/src/r_cosh.c
+      igraph/src/r_dim.c
+      igraph/src/r_exp.c
+      igraph/src/r_imag.c
+      igraph/src/r_int.c
+      igraph/src/r_lg10.c
+      igraph/src/r_log.c
+      igraph/src/r_mod.c
+      igraph/src/r_nint.c
+      igraph/src/r_sign.c
+      igraph/src/r_sin.c
+      igraph/src/r_sinh.c
+      igraph/src/r_sqrt.c
+      igraph/src/r_tan.c
+      igraph/src/r_tanh.c
+      igraph/src/random.c
+      igraph/src/random_walk.c
+      igraph/src/rbinom.c
+      igraph/src/rdfmt.c
+      igraph/src/reorder.c
+      igraph/src/rewind.c
+      igraph/src/rsfe.c
+      igraph/src/rsli.c
+      igraph/src/rsne.c
+      igraph/src/s_cat.c
+      igraph/src/s_cmp.c
+      igraph/src/s_copy.c
+      igraph/src/s_paus.c
+      igraph/src/s_rnge.c
+      igraph/src/s_stop.c
+      igraph/src/sampling.c
+      igraph/src/sbm.c
+      igraph/src/scan.c
+      igraph/src/scg.c
+      igraph/src/scg_approximate_methods.c
+      igraph/src/scg_exact_scg.c
+      igraph/src/scg_kmeans.c
+      igraph/src/scg_optimal_method.c
+      igraph/src/scg_utils.c
+      igraph/src/second.c
+      igraph/src/separators.c
+      igraph/src/sfe.c
+      igraph/src/sig_die.c
+      igraph/src/signal_.c
+      igraph/src/signbit.c
+      igraph/src/sir.c
+      igraph/src/spanning_trees.c
+      igraph/src/sparsemat.c
+      igraph/src/spectral_properties.c
+      igraph/src/spmatrix.c
+      igraph/src/st-cuts.c
+      igraph/src/statusbar.c
+      igraph/src/structural_properties.c
+      igraph/src/structure_generators.c
+      igraph/src/sue.c
+      igraph/src/sugiyama.c
+      igraph/src/system_.c
+      igraph/src/topology.c
+      igraph/src/triangles.c
+      igraph/src/type_indexededgelist.c
+      igraph/src/types.c
+      igraph/src/typesize.c
+      igraph/src/uio.c
+      igraph/src/uninit.c
+      igraph/src/util.c
+      igraph/src/vector.c
+      igraph/src/vector_ptr.c
+      igraph/src/version.c
+      igraph/src/visitors.c
+      igraph/src/wref.c
+      igraph/src/wrtfmt.c
+      igraph/src/wsfe.c
+      igraph/src/wsle.c
+      igraph/src/wsne.c
+      igraph/src/xerbla.c
+      igraph/src/xwsne.c
+      igraph/src/z_abs.c
+      igraph/src/z_cos.c
+      igraph/src/z_div.c
+      igraph/src/z_exp.c
+      igraph/src/z_log.c
+      igraph/src/z_sin.c
+      igraph/src/z_sqrt.c
+      igraph/src/zeroin.c
+  cxx-sources:
+      igraph/src/clustertool.cpp
+      igraph/src/degree_sequence.cpp
+      igraph/src/DensityGrid.cpp
+      igraph/src/DensityGrid_3d.cpp
+      igraph/src/drl_graph.cpp
+      igraph/src/drl_graph_3d.cpp
+      igraph/src/drl_layout.cpp
+      igraph/src/drl_layout_3d.cpp
+      igraph/src/drl_parse.cpp
+      igraph/src/gengraph_box_list.cpp
+      igraph/src/gengraph_degree_sequence.cpp
+      igraph/src/gengraph_graph_molloy_hash.cpp
+      igraph/src/gengraph_graph_molloy_optimized.cpp
+      igraph/src/gengraph_mr-connected.cpp
+      igraph/src/gengraph_powerlaw.cpp
+      igraph/src/gengraph_random.cpp
+      igraph/src/NetDataTypes.cpp
+      igraph/src/NetRoutines.cpp
+      igraph/src/pottsmodel_2.cpp
+      igraph/src/prpack.cpp
+      igraph/src/prpack_base_graph.cpp
+      igraph/src/prpack_igraph_graph.cpp
+      igraph/src/prpack_preprocessed_ge_graph.cpp
+      igraph/src/prpack_preprocessed_gs_graph.cpp
+      igraph/src/prpack_preprocessed_scc_graph.cpp
+      igraph/src/prpack_preprocessed_schur_graph.cpp
+      igraph/src/prpack_result.cpp
+      igraph/src/prpack_solver.cpp
+      igraph/src/prpack_utils.cpp
+      igraph/src/walktrap.cpp
+      igraph/src/walktrap_communities.cpp
+      igraph/src/walktrap_graph.cpp
+      igraph/src/walktrap_heap.cpp
+      igraph/src/bliss.cc
+      igraph/src/bliss_heap.cc
+      igraph/src/defs.cc
+      igraph/src/graph.cc
+      igraph/src/igraph_hrg.cc
+      igraph/src/igraph_hrg_types.cc
+      igraph/src/infomap.cc
+      igraph/src/infomap_FlowGraph.cc
+      igraph/src/infomap_Greedy.cc
+      igraph/src/infomap_Node.cc
+      igraph/src/orbit.cc
+      igraph/src/partition.cc
+      igraph/src/uintseqhash.cc
+      igraph/src/utils.cc
+  extra-libraries:
+      stdc++
+  build-tool-depends:
+      c2hs:c2hs >=0.25.0
+  build-depends:
+      base >=4.10 && <5.0
+    , bytestring >=0.9
+    , cereal
+    , conduit >=1.3.0
+    , containers
+    , data-ordlist
+    , primitive
+    , singletons >=3.0
+    , singletons-base
+    , singletons-th
+  default-language: Haskell2010
+
+test-suite test
+  type: exitcode-stdio-1.0
+  main-is: test.hs
+  other-modules:
+      Test.Basic
+      Test.Attributes
+      Test.Algorithms
+      Test.Utils
+  hs-source-dirs:
+      tests
+  ghc-options: -threaded
+  build-depends:
+      base
+    , cereal
+    , conduit >=1.3.0
+    , data-ordlist
+    , haskell-igraph
+    , matrices
+    , random
+    , tasty
+    , tasty-golden
+    , tasty-hunit
+  default-language: Haskell2010
diff --git a/igraph/AUTHORS b/igraph/AUTHORS
--- a/igraph/AUTHORS
+++ b/igraph/AUTHORS
@@ -2,3 +2,5 @@
 Tamas Nepusz <ntamas@gmail.com>
 Szabolcs Horvat <szhorvat@gmail.com>
 Vincent Traag <v.a.traag@cwts.leidenuniv.nl>
+Fabio Zanini <fabio.zanini@unsw.edu.au>
+
diff --git a/igraph/include/DensityGrid.h b/igraph/include/DensityGrid.h
--- a/igraph/include/DensityGrid.h
+++ b/igraph/include/DensityGrid.h
@@ -36,17 +36,14 @@
 
 // Compile time adjustable parameters
 
-
-#include <deque>
-
-using namespace std;
-
 #include "drl_layout.h"
 #include "drl_Node.h"
 #ifdef MUSE_MPI
     #include <mpi.h>
 #endif
 
+#include <deque>
+
 namespace drl {
 
 class DensityGrid {
@@ -74,7 +71,7 @@
     // new dynamic variables -- SBM
     float (*fall_off)[RADIUS * 2 + 1];
     float (*Density)[GRID_SIZE];
-    deque<Node>* Bins;
+    std::deque<Node>* Bins;
 
     // old static variables
     //float fall_off[RADIUS*2+1][RADIUS*2+1];
diff --git a/igraph/include/DensityGrid_3d.h b/igraph/include/DensityGrid_3d.h
--- a/igraph/include/DensityGrid_3d.h
+++ b/igraph/include/DensityGrid_3d.h
@@ -36,17 +36,14 @@
 
 // Compile time adjustable parameters
 
-
-#include <deque>
-
-using namespace std;
-
 #include "drl_layout_3d.h"
 #include "drl_Node_3d.h"
 #ifdef MUSE_MPI
     #include <mpi.h>
 #endif
 
+#include <deque>
+
 namespace drl3d {
 
 class DensityGrid {
@@ -74,7 +71,7 @@
     // new dynamic variables -- SBM
     float (*fall_off)[RADIUS * 2 + 1][RADIUS * 2 + 1];
     float (*Density)[GRID_SIZE][GRID_SIZE];
-    deque<Node>* Bins;
+    std::deque<Node>* Bins;
 
     // old static variables
     //float fall_off[RADIUS*2+1][RADIUS*2+1];
diff --git a/igraph/include/NetDataTypes.h b/igraph/include/NetDataTypes.h
--- a/igraph/include/NetDataTypes.h
+++ b/igraph/include/NetDataTypes.h
@@ -43,7 +43,7 @@
 #ifndef NETDATATYPES_H
 #define NETDATATYPES_H
 
-#include <string.h>
+#include <cstring>
 
 //###########################################################################################
 
@@ -449,7 +449,7 @@
 
 template <class DATA>
 HugeArray<DATA>::HugeArray(void) {
-    max_bit_left = 1 << 31; //wir setzen das 31. Bit auf 1
+    max_bit_left = 1UL << 31; //wir setzen das 31. Bit auf 1
     size = 2;
     max_index = 0;
     highest_field_index = 0;
@@ -486,7 +486,7 @@
         shift_index++;
     }
     h_index.field_index = 31 - shift_index;   // das hoechste  besetzte Bit im Index
-    help_index = 1 << h_index.field_index;  // in help_index wird das hoechste besetzte Bit von Index gesetzt
+    help_index = 1UL << h_index.field_index;  // in help_index wird das hoechste besetzte Bit von Index gesetzt
     h_index.in_field_index = (index ^ help_index); // index XOR help_index, womit alle bits unter dem hoechsten erhalten bleiben
     return h_index;
 }
@@ -497,7 +497,7 @@
     unsigned long data_size;
     while (size < index + 1) {
         highest_field_index++;
-        data_size = 1 << highest_field_index;
+        data_size = 1UL << highest_field_index;
         data = new DATA[data_size];
         for (unsigned long i = 0; i < data_size; i++) {
             data[i] = 0;
diff --git a/igraph/include/bliss/bignum.hh b/igraph/include/bliss/bignum.hh
--- a/igraph/include/bliss/bignum.hh
+++ b/igraph/include/bliss/bignum.hh
@@ -21,7 +21,7 @@
 */
 
 #include <cstdlib>
-#include <cstdio>
+// #include <cstdio>
 #include <cmath>
 #include <cstring>
 #include <sstream>
@@ -111,7 +111,7 @@
   /**
    * Print the number in the file stream \a fp.
    */
-  size_t print(FILE* const fp) const {return fprintf(fp, "%Lg", v); }
+  // size_t print(FILE* const fp) const {return fprintf(fp, "%Lg", v); }
 
   int tostring(char **str) const {
     int size=static_cast<int>( (std::log(std::abs(v))/std::log(10.0))+4 );
diff --git a/igraph/include/bliss/defs.hh b/igraph/include/bliss/defs.hh
--- a/igraph/include/bliss/defs.hh
+++ b/igraph/include/bliss/defs.hh
@@ -29,11 +29,6 @@
 #  define BLISS_USE_GMP
 #endif
 
-#ifdef USING_R
-#include <R.h>
-#define fatal_error(...) (error(__VA_ARGS__))
-#endif
-
 namespace bliss {
 
 /**
@@ -47,9 +42,7 @@
  * There should not be a return from this function but exit or
  * a jump to code that deallocates the AbstractGraph instance that called this.
  */
-#ifndef USING_R
 void fatal_error(const char* fmt, ...);
-#endif
 
 
 #if defined(BLISS_DEBUG)
diff --git a/igraph/include/bliss/graph.hh b/igraph/include/bliss/graph.hh
--- a/igraph/include/bliss/graph.hh
+++ b/igraph/include/bliss/graph.hh
@@ -29,7 +29,7 @@
   class AbstractGraph;
 }
 
-#include <cstdio>
+// #include <cstdio>
 #include <vector>
 #include "kstack.hh"
 #include "kqueue.hh"
@@ -81,6 +81,7 @@
 public:
   Stats() { reset(); }
   /** Print the statistics. */
+  /*
   size_t print(FILE* const fp) const
   {
     size_t r = 0;
@@ -94,6 +95,7 @@
     fflush(fp);
     return r;
   }
+  */
   /** An approximation (due to possible overflows/rounding errors) of
    * the size of the automorphism group. */
   long double get_group_size_approx() const {return group_size_approx;}
@@ -241,6 +243,7 @@
 						  const unsigned int* aut),
 				     void* hook_user_param);
 
+#if 0
   /**
    * Write the graph to a file in a variant of the DIMACS format.
    * See the <A href="http://www.tcs.hut.fi/Software/bliss/">bliss website</A>
@@ -264,6 +267,7 @@
    * \param file_name  the name of the file to which the graph is written
    */
   virtual void write_dot(const char * const file_name) = 0;
+#endif
 
   /**
    * Get a hash value for the graph.
@@ -294,7 +298,7 @@
   unsigned int verbose_level;
   /** \internal
    * The output stream for verbose output. */
-  FILE *verbstr;
+  // FILE *verbstr;
 protected:
 
   /** \internal
@@ -391,7 +395,7 @@
    * Data structures and routines for refining the partition p into equitable
    */
   Heap neighbour_heap;
-  virtual bool split_neighbourhood_of_unit_cell(Partition::Cell *) = 0;
+  virtual bool split_neighbourhood_of_unit_cell(Partition::Cell * const) = 0;
   virtual bool split_neighbourhood_of_cell(Partition::Cell * const) = 0;
   void refine_to_equitable();
   void refine_to_equitable(Partition::Cell * const unit_cell);
@@ -658,6 +662,7 @@
    */
   ~Graph();
 
+#if 0
   /**
    * Read the graph from the file \a fp in a variant of the DIMACS format.
    * See the <A href="http://www.tcs.hut.fi/Software/bliss/">bliss website</A>
@@ -690,6 +695,7 @@
    * \copydoc AbstractGraph::write_dot(const char * const file_name)
    */
   void write_dot(const char* const file_name);
+#endif
 
   /**
    * \copydoc AbstractGraph::is_automorphism(const std::vector<unsigned int>& perm) const
@@ -898,6 +904,7 @@
    */
   ~Digraph();
 
+#if 0
   /**
    * Read the graph from the file \a fp in a variant of the DIMACS format.
    * See the <A href="http://www.tcs.hut.fi/Software/bliss/">bliss website</A>
@@ -928,6 +935,7 @@
    * \copydoc AbstractGraph::write_dot(const char * const file_name)
    */
   void write_dot(const char * const file_name);
+#endif
 
   /**
    * \copydoc AbstractGraph::is_automorphism(const std::vector<unsigned int>& perm) const
diff --git a/igraph/include/bliss/partition.hh b/igraph/include/bliss/partition.hh
--- a/igraph/include/bliss/partition.hh
+++ b/igraph/include/bliss/partition.hh
@@ -25,7 +25,7 @@
 }
 
 #include <cstdlib>
-#include <cstdio>
+//#include <cstdio>
 #include <climits>
 #include "kstack.hh"
 #include "kqueue.hh"
@@ -186,12 +186,12 @@
   /**
    * Print the partition into the file stream \a fp.
    */
-  size_t print(FILE* const fp, const bool add_newline = true) const;
+  // size_t print(FILE* const fp, const bool add_newline = true) const;
 
   /**
    * Print the partition cell sizes into the file stream \a fp.
    */
-  size_t print_signature(FILE* const fp, const bool add_newline = true) const;
+  // size_t print_signature(FILE* const fp, const bool add_newline = true) const;
 
   /*
    * Splits the Cell \a cell into [cell_1,...,cell_n]
diff --git a/igraph/include/bliss/uintseqhash.hh b/igraph/include/bliss/uintseqhash.hh
--- a/igraph/include/bliss/uintseqhash.hh
+++ b/igraph/include/bliss/uintseqhash.hh
@@ -1,7 +1,7 @@
 #ifndef BLISS_UINTSEQHASH_HH
 #define BLISS_UINTSEQHASH_HH
 
-#include <cstdio>
+// #include <cstdio>
 
 /*
   Copyright (c) 2003-2015 Tommi Junttila
diff --git a/igraph/include/bliss/utils.hh b/igraph/include/bliss/utils.hh
--- a/igraph/include/bliss/utils.hh
+++ b/igraph/include/bliss/utils.hh
@@ -26,11 +26,12 @@
  *
  */
 
-#include <cstdio>
-using namespace std;
+//#include <cstdio>
+#include <vector>
 
 namespace bliss {
 
+#if 0
 /**
  * Print the permutation \a perm of {0,...,N-1} in the cycle format
  * in the file stream \a fp.
@@ -51,6 +52,7 @@
 void print_permutation(FILE* fp,
 		       const std::vector<unsigned int>& perm,
 		       const unsigned int offset = 0);
+#endif
 
 /**
  * Check whether \a perm is a valid permutation on {0,...,N-1}.
diff --git a/igraph/include/cliquer/set.h b/igraph/include/cliquer/set.h
--- a/igraph/include/cliquer/set.h
+++ b/igraph/include/cliquer/set.h
diff --git a/igraph/include/config.h b/igraph/include/config.h
--- a/igraph/include/config.h
+++ b/igraph/include/config.h
@@ -11,6 +11,7 @@
 #define HAVE_RINTF 1
 #define HAVE_ROUND 1
 #define HAVE_SNPRINTF 1
+#undef HAVE_ISFINITE
 
 /* libraries */
 #define HAVE_MEMORY_H 1
@@ -18,8 +19,10 @@
 #define HAVE_STRINGS_H 1
 #define HAVE_STRING_H 1
 
+#define HAVE_TLS 1
 #define IGRAPH_F77_SAVE static IGRAPH_THREAD_LOCAL
-#define IGRAPH_THREAD_LOCAL 
+#define IGRAPH_THREAD_LOCAL __thread
+#define TLS __thread
 
 #define INTERNAL_ARPACK 1
 #define INTERNAL_BLAS 1
@@ -27,13 +30,15 @@
 #define INTERNAL_GLPK 1
 #define INTERNAL_LAPACK 1
 
+
 #define LT_OBJDIR ".libs/"
 #define PACKAGE "igraph"
 #define PACKAGE_BUGREPORT "igraph@igraph.org"
 #define PACKAGE_NAME "igraph"
-#define PACKAGE_STRING "igraph 0.8.0"
+#define PACKAGE_STRING "igraph 0.8.5"
 #define PACKAGE_TARNAME "igraph"
 #define PACKAGE_URL ""
-#define PACKAGE_VERSION "0.8.0"
+#define PACKAGE_VERSION "0.8.5"
 #define STDC_HEADERS 1
-#define VERSION "0.8.0"
+#define VERSION "0.8.5"
+#undef YYTEXT_POINTER
diff --git a/igraph/include/drl_graph.h b/igraph/include/drl_graph.h
--- a/igraph/include/drl_graph.h
+++ b/igraph/include/drl_graph.h
@@ -37,6 +37,10 @@
 #include "DensityGrid.h"
 #include "igraph_layout.h"
 
+#include <map>
+#include <vector>
+#include <ctime>
+
 namespace drl {
 
 // layout schedule information
@@ -81,8 +85,8 @@
     void update_nodes ( );
     float Compute_Node_Energy ( int node_ind );
     void Solve_Analytic ( int node_ind, float &pos_x, float &pos_y );
-    void get_positions ( vector<int> &node_indices, float return_positions[2 * MAX_PROCS] );
-    void update_density ( vector<int> &node_indices,
+    void get_positions ( std::vector<int> &node_indices, float return_positions[2 * MAX_PROCS] );
+    void update_density ( std::vector<int> &node_indices,
                           float old_positions[2 * MAX_PROCS],
                           float new_positions[2 * MAX_PROCS] );
     void update_node_pos ( int node_ind,
@@ -95,11 +99,11 @@
     // graph decomposition information
     int num_nodes;                  // number of nodes in graph
     float highest_sim;              // highest sim for normalization
-    map <int, int> id_catalog;      // id_catalog[file id] = internal id
-    map <int, map <int, float> > neighbors;     // neighbors of nodes on this proc.
+    std::map <int, int> id_catalog;      // id_catalog[file id] = internal id
+    std::map <int, std::map <int, float> > neighbors;     // neighbors of nodes on this proc.
 
     // graph layout information
-    vector<Node> positions;
+    std::vector<Node> positions;
     DensityGrid density_server;
 
     // original VxOrd information
diff --git a/igraph/include/drl_graph_3d.h b/igraph/include/drl_graph_3d.h
--- a/igraph/include/drl_graph_3d.h
+++ b/igraph/include/drl_graph_3d.h
@@ -37,6 +37,10 @@
 #include "DensityGrid_3d.h"
 #include "igraph_layout.h"
 
+#include <map>
+#include <vector>
+#include <ctime>
+
 namespace drl3d {
 
 // layout schedule information
@@ -73,8 +77,8 @@
     void update_nodes ( );
     float Compute_Node_Energy ( int node_ind );
     void Solve_Analytic ( int node_ind, float &pos_x, float &pos_y, float &pos_z );
-    void get_positions ( vector<int> &node_indices, float return_positions[3 * MAX_PROCS] );
-    void update_density ( vector<int> &node_indices,
+    void get_positions ( std::vector<int> &node_indices, float return_positions[3 * MAX_PROCS] );
+    void update_density ( std::vector<int> &node_indices,
                           float old_positions[3 * MAX_PROCS],
                           float new_positions[3 * MAX_PROCS] );
     void update_node_pos ( int node_ind,
@@ -87,11 +91,11 @@
     // graph decomposition information
     int num_nodes;                  // number of nodes in graph
     float highest_sim;              // highest sim for normalization
-    map <int, int> id_catalog;      // id_catalog[file id] = internal id
-    map <int, map <int, float> > neighbors;     // neighbors of nodes on this proc.
+    std::map <int, int> id_catalog;      // id_catalog[file id] = internal id
+    std::map <int, std::map <int, float> > neighbors;     // neighbors of nodes on this proc.
 
     // graph layout information
-    vector<Node> positions;
+    std::vector<Node> positions;
     DensityGrid density_server;
 
     // original VxOrd information
diff --git a/igraph/include/drl_parse.h b/igraph/include/drl_parse.h
--- a/igraph/include/drl_parse.h
+++ b/igraph/include/drl_parse.h
@@ -37,6 +37,8 @@
     #include <mpi.h>
 #endif
 
+#include <string>
+
 namespace drl {
 
 class parse {
@@ -49,10 +51,10 @@
     ~parse () {}
 
     // user parameters
-    string sim_file;        // .sim file
-    string coord_file;      // .coord file
-    string parms_file;      // .parms file
-    string real_file;       // .real file
+    std::string sim_file;        // .sim file
+    std::string coord_file;      // .coord file
+    std::string parms_file;      // .parms file
+    std::string real_file;       // .real file
 
     int rand_seed;      // random seed int >= 0
     float edge_cut;         // edge cutting real [0,1]
diff --git a/igraph/include/gengraph_box_list.h b/igraph/include/gengraph_box_list.h
--- a/igraph/include/gengraph_box_list.h
+++ b/igraph/include/gengraph_box_list.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -27,12 +27,6 @@
 
 #ifndef _BOX_LIST_H
 #define _BOX_LIST_H
-
-#ifndef _MSC_VER
-    #ifndef register
-        #define register
-    #endif
-#endif
 
 namespace gengraph {
 
diff --git a/igraph/include/gengraph_definitions.h b/igraph/include/gengraph_definitions.h
--- a/igraph/include/gengraph_definitions.h
+++ b/igraph/include/gengraph_definitions.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -21,12 +21,6 @@
 #ifndef DEFINITIONS_H
 #define DEFINITIONS_H
 
-#ifndef _MSC_VER
-    #ifndef register
-        #define register
-    #endif
-#endif
-
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
@@ -124,7 +118,7 @@
   if(fabs(x)<1e-6) return x+0.5*x*x+0.333333333333333*x*x*x;
   else return log(1.0+x);
 }
-//*/
+*/
 
 
 //Fast search or replace
@@ -197,7 +191,7 @@
 static int _random_bits = 0;
 
 inline int random_bit() {
-    register int a = _random_bits;
+    int a = _random_bits;
     _random_bits = a >> 1;
     if (_random_bits_stored--) {
         return a & 0x1;
diff --git a/igraph/include/gengraph_degree_sequence.h b/igraph/include/gengraph_degree_sequence.h
--- a/igraph/include/gengraph_degree_sequence.h
+++ b/igraph/include/gengraph_degree_sequence.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
diff --git a/igraph/include/gengraph_graph_molloy_hash.h b/igraph/include/gengraph_graph_molloy_hash.h
--- a/igraph/include/gengraph_graph_molloy_hash.h
+++ b/igraph/include/gengraph_graph_molloy_hash.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -209,7 +209,7 @@
       // same, but when multiple shortest path are possible, average the weights.
       double *vertex_betweenness_asp(bool trivial_path);
     //___________________________________________________________________________________
-    //*/
+    */
 
 };
 
diff --git a/igraph/include/gengraph_graph_molloy_optimized.h b/igraph/include/gengraph_graph_molloy_optimized.h
--- a/igraph/include/gengraph_graph_molloy_optimized.h
+++ b/igraph/include/gengraph_graph_molloy_optimized.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -265,7 +265,7 @@
       bool try_shuffle(int T, int K);
 
     //___________________________________________________________________________________
-    //*/
+    */
 
     /*___________________________________________________________________________________
       Not to use anymore : replaced by vertex_betweenness()     22/04/2005
@@ -277,7 +277,7 @@
       // same, but when multiple shortest path are possible, average the weights.
       double *vertex_betweenness_asp(bool trivial_path);
     //___________________________________________________________________________________
-    //*/
+    */
 
 };
 
diff --git a/igraph/include/gengraph_hash.h b/igraph/include/gengraph_hash.h
--- a/igraph/include/gengraph_hash.h
+++ b/igraph/include/gengraph_hash.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
diff --git a/igraph/include/gengraph_header.h b/igraph/include/gengraph_header.h
--- a/igraph/include/gengraph_header.h
+++ b/igraph/include/gengraph_header.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -41,17 +41,6 @@
 }
 
 }
-
-#ifdef _WIN32
-#include <process.h>
-#include <windows.h>
-void set_priority_low() {
-    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, _getpid());
-    SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS);
-}
-#else
-#include <unistd.h>
-#endif
 
 namespace gengraph {
 
diff --git a/igraph/include/gengraph_powerlaw.h b/igraph/include/gengraph_powerlaw.h
--- a/igraph/include/gengraph_powerlaw.h
+++ b/igraph/include/gengraph_powerlaw.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
diff --git a/igraph/include/gengraph_qsort.h b/igraph/include/gengraph_qsort.h
--- a/igraph/include/gengraph_qsort.h
+++ b/igraph/include/gengraph_qsort.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -24,10 +24,6 @@
 #include <assert.h>
 #include <stdio.h>
 
-#ifndef register
-    #define register
-#endif
-
 namespace gengraph {
 
 //___________________________________________________________________________
@@ -63,7 +59,7 @@
         return;
     }
     for (int i = 1; i < t; i++) {
-        register int *w = v + i;
+        int *w = v + i;
         int tmp = *w;
         while (w != v && *(w - 1) > tmp) {
             *w = *(w - 1);
@@ -147,7 +143,7 @@
         return;
     }
     for (int i = 1; i < t; i++) {
-        register double *w = v + i;
+        double *w = v + i;
         double tmp = *w;
         while (w != v && *(w - 1) > tmp) {
             *w = *(w - 1);
@@ -260,7 +256,7 @@
     int mx = mem[0];
     int mn = mem[0];
     for (yo = mem + n - 1; yo != mem; yo--) {
-        register int x = *yo;
+        int x = *yo;
         if (x > mx) {
             mx = x;
         }
@@ -399,7 +395,7 @@
         return;
     }
     for (int i = 1; i < t; i++) {
-        register int *w = v + i;
+        int *w = v + i;
         int tmp = *w;
         while (w != v && lex_comp(l[tmp], l[*(w - 1)], s) < 0) {
             *w = *(w - 1);
@@ -521,7 +517,7 @@
         return;
     }
     for (int i = 1; i < t; i++) {
-        register int *w = v + i;
+        int *w = v + i;
         int tmp = *w;
         while (w != v && mix_comp_indirect(key, tmp, *(w - 1), neigh, degs) < 0) {
             *w = *(w - 1);
diff --git a/igraph/include/gengraph_random.h b/igraph/include/gengraph_random.h
--- a/igraph/include/gengraph_random.h
+++ b/igraph/include/gengraph_random.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -22,8 +22,6 @@
 #define RNG_H
 
 #include "igraph_random.h"
-#include <iostream>
-using namespace std;
 
 namespace KW_RNG {
 
diff --git a/igraph/include/gengraph_vertex_cover.h b/igraph/include/gengraph_vertex_cover.h
--- a/igraph/include/gengraph_vertex_cover.h
+++ b/igraph/include/gengraph_vertex_cover.h
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -28,10 +28,7 @@
 // Moreover, vertex_cover() keeps links[] intact, permuting only the adjacency lists
 
 #include "gengraph_box_list.h"
-
-#ifndef register
-    #define register
-#endif
+#include <cstddef>
 
 namespace gengraph {
 
@@ -57,9 +54,9 @@
         if (!bl.is_empty()) {
             v = bl.get_max();
             int *w = neigh[v];
-            register int v2 = *(w++);
-            register int dm = deg[v2];
-            register int k = deg[v] - 1;
+            int v2 = *(w++);
+            int dm = deg[v2];
+            int k = deg[v] - 1;
             while (k--) if (deg[*(w++)] > dm) {
                     v2 = *(w - 1);
                     dm = deg[v2];
diff --git a/igraph/include/heap.pmt b/igraph/include/heap.pmt
--- a/igraph/include/heap.pmt
+++ b/igraph/include/heap.pmt
@@ -33,6 +33,12 @@
 #define LEFTCHILD(x)  (((x)+1)*2-1)
 #define RIGHTCHILD(x) (((x)+1)*2)
 
+/* Define internal functions */
+void FUNCTION(igraph_heap, i_build)(BASE* arr, long int size, long int head);
+void FUNCTION(igraph_heap, i_shift_up)(BASE* arr, long int size, long int elem);
+void FUNCTION(igraph_heap, i_sink)(BASE* arr, long int size, long int head);
+void FUNCTION(igraph_heap, i_switch)(BASE* arr, long int e1, long int e2);
+
 /**
  * \ingroup heap
  * \function igraph_heap_init
diff --git a/igraph/include/hrg_dendro.h b/igraph/include/hrg_dendro.h
--- a/igraph/include/hrg_dendro.h
+++ b/igraph/include/hrg_dendro.h
@@ -65,18 +65,15 @@
 #ifndef IGRAPH_HRG_DENDRO
 #define IGRAPH_HRG_DENDRO
 
-#include <iostream>
-#include <fstream>
-#include <cstdio>
-#include <cmath>
-
 #include "hrg_graph.h"
 #include "hrg_rbtree.h"
 #include "hrg_splittree_eq.h"
 
 #include "igraph_hrg.h"
 
-using namespace std;
+#include <string>
+#include <cmath>
+
 using namespace fitHRG;
 
 namespace fitHRG {
@@ -105,7 +102,7 @@
     int    x;
     int y;
     short int t;
-    string sp;
+    std::string sp;
 };
 struct child {
     int index;
@@ -147,7 +144,7 @@
 
 class split {
 public:
-    string s;           // partition assignment of leaf vertices
+    std::string s;           // partition assignment of leaf vertices
     split(): s("") { }
     ~split() { }
     void initializeSplit(const int n) {
@@ -157,7 +154,7 @@
         }
     }
     bool checkSplit() {
-        if (s.empty() || s.find("-", 0) != string::npos) {
+        if (s.empty() || s.find("-", 0) != std::string::npos) {
             return false;
         } else {
             return true;
@@ -181,7 +178,7 @@
 class interns {
 private:
     ipair* edgelist;   // list of internal edges represented
-    string* splitlist; // split representation of the internal edges
+    std::string* splitlist; // split representation of the internal edges
     int** indexLUT;    // table of indices of internal edges in edgelist
     int q;         // number of internal edges
     int count;         // (for adding edges) edgelist index of new edge to add
@@ -196,9 +193,9 @@
     // returns a uniformly random internal edge, O(1)
     ipair* getRandomEdge();
     // returns the ith split of the splitlist, O(1)
-    string getSplit(const int);
+    std::string getSplit(const int);
     // replace an existing split, O(1)
-    bool replaceSplit(const int, const string);
+    bool replaceSplit(const int, const std::string);
     // swaps two edges, O(1)
     bool swapEdges(const int, const int, const short int, const int,
                    const int, const short int);
@@ -250,12 +247,12 @@
     // return path to root from leaf
     list* binarySearchFind(const double);
     // build split for this internal edge
-    string buildSplit(elementd*);
+    std::string buildSplit(elementd*);
     // compute number of edges between two internal subtrees
     int computeEdgeCount(const int, const short int, const int,
                          const short int);
     // (consensus tree) counts children
-    int countChildren(const string);
+    int countChildren(const std::string);
     // find internal node of D that is common ancestor of i,j
     elementd* findCommonAncestor(list**, const int, const int);
     // return reverse of path to leaf from root
diff --git a/igraph/include/hrg_graph.h b/igraph/include/hrg_graph.h
--- a/igraph/include/hrg_graph.h
+++ b/igraph/include/hrg_graph.h
@@ -61,13 +61,11 @@
 #ifndef IGRAPH_HRG_GRAPH
 #define IGRAPH_HRG_GRAPH
 
-#include <cstdio>
-#include <cstring>
-#include <cstdlib>
-
 #include "hrg_rbtree.h"
 
-using namespace std;
+#include <string>
+#include <cstring>
+#include <cstdlib>
 
 namespace fitHRG {
 
@@ -96,7 +94,7 @@
 #define IGRAPH_HRG_VERT
 class vert {
 public:
-    string name;           // (external) name of vertex
+    std::string name;           // (external) name of vertex
     int degree;            // degree of this vertex
 
     vert(): name(""), degree(0) { }
@@ -122,7 +120,7 @@
     // returns degree of vertex i
     int getDegree(const int);
     // returns name of vertex i
-    string getName(const int);
+    std::string getName(const int);
     // returns edge list of vertex i
     edge* getNeighborList(const int);
     // return ptr to histogram of edge (i,j)
@@ -148,7 +146,7 @@
     // allocate edge histograms
     void setAdjacencyHistograms(const int);
     // set name of vertex i
-    bool setName(const int, const string);
+    bool setName(const int, const std::string);
 
 private:
     bool predict;      // do we need prediction?
diff --git a/igraph/include/hrg_graph_simp.h b/igraph/include/hrg_graph_simp.h
--- a/igraph/include/hrg_graph_simp.h
+++ b/igraph/include/hrg_graph_simp.h
@@ -60,14 +60,11 @@
 #ifndef IGRAPH_HRG_SIMPLEGRAPH
 #define IGRAPH_HRG_SIMPLEGRAPH
 
-#include <cstdio>
-#include <cstring>
-#include <cstdlib>
-
 #include "hrg_rbtree.h"
 #include "hrg_dendro.h"
 
-using namespace std;
+#include <cstring>
+#include <cstdlib>
 
 namespace fitHRG {
 
@@ -89,7 +86,7 @@
 #define IGRAPH_HRG_SIMPLEVERT
 class simpleVert {
 public:
-    string name;          // (external) name of vertex
+    std::string name;          // (external) name of vertex
     int degree;           // degree of this vertex
     int group_true;       // index of vertex's true group
 
@@ -129,7 +126,7 @@
     // returns group label of vertex i
     int getGroupLabel(const int);
     // returns name of vertex i
-    string getName(const int);
+    std::string getName(const int);
     // returns edge list of vertex i
     simpleEdge* getNeighborList(const int);
     // return pointer to a node
@@ -141,7 +138,7 @@
     // returns n
     int getNumNodes();
     // set name of vertex i
-    bool setName(const int, const string);
+    bool setName(const int, const std::string);
 
 private:
     simpleVert* nodes;        // list of nodes
diff --git a/igraph/include/hrg_rbtree.h b/igraph/include/hrg_rbtree.h
--- a/igraph/include/hrg_rbtree.h
+++ b/igraph/include/hrg_rbtree.h
@@ -55,10 +55,6 @@
 #ifndef IGRAPH_HRG_RBTREE
 #define IGRAPH_HRG_RBTREE
 
-#include <iostream>
-
-using namespace std;
-
 namespace fitHRG {
 
 // ******** Basic Structures *********************************************
diff --git a/igraph/include/hrg_splittree_eq.h b/igraph/include/hrg_splittree_eq.h
--- a/igraph/include/hrg_splittree_eq.h
+++ b/igraph/include/hrg_splittree_eq.h
@@ -62,9 +62,7 @@
 #ifndef IGRAPH_HRG_SPLITTREE
 #define IGRAPH_HRG_SPLITTREE
 
-#include <iostream>
-
-using namespace std;
+#include <string>
 
 namespace fitHRG {
 
@@ -74,7 +72,7 @@
 #define IGRAPH_HRG_SLIST
 class slist {
 public:
-    string x;         // stored elementd in linked-list
+    std::string x;         // stored elementd in linked-list
     slist* next;          // pointer to next elementd
     slist(): x(""), next(0) { }
     ~slist() { }
@@ -83,7 +81,7 @@
 
 class keyValuePairSplit {
 public:
-    string x;         // elementsp split (string)
+    std::string x;         // elementsp split (string)
     double y;         // stored weight   (double)
     int c;            // stored count    (int)
     keyValuePairSplit* next;  // linked-list pointer
@@ -95,7 +93,7 @@
 
 class elementsp {
 public:
-    string split;             // split represented as a string
+    std::string split;             // split represented as a string
     double weight;            // total weight of this split
     int count;                // number of observations of this split
 
@@ -149,21 +147,21 @@
     // default constructor/destructor
     splittree(); ~splittree();
     // returns value associated with searchKey
-    double returnValue(const string);
+    double returnValue(const std::string);
     // returns T if searchKey found, and points foundNode at the
     // corresponding node
-    elementsp* findItem(const string);
+    elementsp* findItem(const std::string);
     // update total_count and total_weight
     void finishedThisRound();
     // insert a new key with stored value
-    bool insertItem(string, double);
+    bool insertItem(std::string, double);
     void clearTree();
     // delete a node with given key
-    void deleteItem(string);
+    void deleteItem(std::string);
     // delete the entire tree
     void deleteTree();
     // return array of keys in tree
-    string* returnArrayOfKeys();
+    std::string* returnArrayOfKeys();
     // return list of keys in tree
     slist* returnListOfKeys();
     // return the tree as a list of keyValuePairSplits
diff --git a/igraph/include/igraph_adjlist.h b/igraph/include/igraph_adjlist.h
--- a/igraph/include/igraph_adjlist.h
+++ b/igraph/include/igraph_adjlist.h
@@ -59,13 +59,12 @@
 /*                 igraph_integer_t no); */
 /**
  * \define igraph_adjlist_get
- * Query a vector in an adjlist
+ * \brief Query a vector in an adjacency list.
  *
  * Returns a pointer to an <type>igraph_vector_int_t</type> object from an
  * adjacency list. The vector can be modified as desired.
  * \param al The adjacency list object.
- * \param no The vertex of which the vertex of adjacent vertices are
- *   returned.
+ * \param no The vertex whose adjacent vertices will be returned.
  * \return Pointer to the <type>igraph_vector_int_t</type> object.
  *
  * Time complexity: O(1).
@@ -93,7 +92,7 @@
 
 /**
  * \define igraph_inclist_get
- * Query a vector in an incidence list
+ * \brief Query a vector in an incidence list.
  *
  * Returns a pointer to an <type>igraph_vector_int_t</type> object from an
  * incidence list containing edge ids. The vector can be modified,
@@ -124,14 +123,14 @@
 /*                     igraph_integer_t no); */
 /**
  * \define igraph_lazy_adjlist_get
- * Query neighbor vertices
+ * \brief Query neighbor vertices.
  *
  * If the function is called for the first time for a vertex then the
  * result is stored in the adjacency list and no further query
  * operations are needed when the neighbors of the same vertex are
  * queried again.
  * \param al The lazy adjacency list.
- * \param no The vertex id to query.
+ * \param no The vertex ID to query.
  * \return Pointer to a vector. It is allowed to modify it and
  *   modification does not affect the original graph.
  *
@@ -159,7 +158,7 @@
 
 /**
  * \define igraph_lazy_inclist_get
- * Query incident edges
+ * \brief Query incident edges.
  *
  * If the function is called for the first time for a vertex, then the
  * result is stored in the incidence list and no further query
@@ -195,7 +194,7 @@
 
 /**
  * \define igraph_adjedgelist_get
- * Query a vector in an incidence list
+ * \brief Query a vector in an incidence list.
  *
  * This macro was superseded by \ref igraph_inclist_get() in igraph 0.6.
  * Please use \ref igraph_inclist_get() instead of this macro.
@@ -214,7 +213,7 @@
 
 /**
  * \define igraph_lazy_adjedgelist_get
- * Query a vector in a lazy incidence list
+ * \brief Query a vector in a lazy incidence list.
  *
  * This macro was superseded by \ref igraph_lazy_inclist_get() in igraph 0.6.
  * Please use \ref igraph_lazy_inclist_get() instead of this macro.
diff --git a/igraph/include/igraph_arpack.h b/igraph/include/igraph_arpack.h
--- a/igraph/include/igraph_arpack.h
+++ b/igraph/include/igraph_arpack.h
@@ -25,8 +25,8 @@
 #include "igraph_vector.h"
 #include "igraph_matrix.h"
 
-#ifndef ARPACK_H
-#define ARPACK_H
+#ifndef IGRAPH_ARPACK_H
+#define IGRAPH_ARPACK_H
 
 #include "igraph_decls.h"
 
@@ -222,34 +222,34 @@
 
 typedef struct igraph_arpack_options_t {
     /* INPUT */
-    char bmat[1];         /* I-standard problem, G-generalized */
-    int n;            /* Dimension of the eigenproblem */
-    char which[2];        /* LA, SA, LM, SM, BE */
-    int nev;                 /* Number of eigenvalues to be computed */
-    igraph_real_t tol;        /* Stopping criterion */
-    int ncv;          /* Number of columns in V */
-    int ldv;          /* Leading dimension of V */
-    int ishift;       /* 0-reverse comm., 1-exact with tridiagonal */
-    int mxiter;              /* Maximum number of update iterations to take */
-    int nb;           /* Block size on the recurrence, only 1 works */
-    int mode;     /* The kind of problem to be solved (1-5)
-                   1: A*x=l*x, A symmetric
-                   2: A*x=l*M*x, A symm. M pos. def.
-                   3: K*x = l*M*x, K symm., M pos. semidef.
-                   4: K*x = l*KG*x, K s. pos. semidef. KG s. indef.
-                   5: A*x = l*M*x, A symm., M symm. pos. semidef. */
-    int start;        /* 0: random, 1: use the supplied vector */
-    int lworkl;       /* Size of temporary storage, default is fine */
-    igraph_real_t sigma;          /* The shift for modes 3,4,5 */
-    igraph_real_t sigmai;     /* The imaginary part of shift for rnsolve */
+    char bmat[1];          /* I-standard problem, G-generalized */
+    int n;                 /* Dimension of the eigenproblem */
+    char which[2];         /* LA, SA, LM, SM, BE */
+    int nev;               /* Number of eigenvalues to be computed */
+    igraph_real_t tol;     /* Stopping criterion */
+    int ncv;               /* Number of columns in V */
+    int ldv;               /* Leading dimension of V */
+    int ishift;            /* 0-reverse comm., 1-exact with tridiagonal */
+    int mxiter;            /* Maximum number of update iterations to take */
+    int nb;                /* Block size on the recurrence, only 1 works */
+    int mode;              /* The kind of problem to be solved (1-5)
+                               1: A*x=l*x, A symmetric
+                               2: A*x=l*M*x, A symm. M pos. def.
+                               3: K*x = l*M*x, K symm., M pos. semidef.
+                               4: K*x = l*KG*x, K s. pos. semidef. KG s. indef.
+                               5: A*x = l*M*x, A symm., M symm. pos. semidef. */
+    int start;             /* 0: random, 1: use the supplied vector */
+    int lworkl;            /* Size of temporary storage, default is fine */
+    igraph_real_t sigma;   /* The shift for modes 3,4,5 */
+    igraph_real_t sigmai;  /* The imaginary part of shift for rnsolve */
     /* OUTPUT */
-    int info;     /* What happened, see docs */
-    int ierr;     /* What happened  in the dseupd call */
-    int noiter;       /* The number of iterations taken */
+    int info;              /* What happened, see docs */
+    int ierr;              /* What happened  in the dseupd call */
+    int noiter;            /* The number of iterations taken */
     int nconv;
-    int numop;        /* Number of OP*x operations */
-    int numopb;       /* Number of B*x operations if BMAT='G' */
-    int numreo;       /* Number of steps of re-orthogonalizations */
+    int numop;             /* Number of OP*x operations */
+    int numopb;            /* Number of B*x operations if BMAT='G' */
+    int numreo;            /* Number of steps of re-orthogonalizations */
     /* INTERNAL */
     int iparam[11];
     int ipntr[14];
diff --git a/igraph/include/igraph_array_pmt.h b/igraph/include/igraph_array_pmt.h
--- a/igraph/include/igraph_array_pmt.h
+++ b/igraph/include/igraph_array_pmt.h
@@ -36,16 +36,16 @@
     #define ARRAY3(m,i,j,k) ((m).data.stor_begin[(m).n1n2*(k)+(m).n1*(j)+(i)])
 #endif
 
-int FUNCTION(igraph_array3, init)(TYPE(igraph_array3) *a, long int n1, long int n2,
+DECLDIR int FUNCTION(igraph_array3, init)(TYPE(igraph_array3) *a, long int n1, long int n2,
                                   long int n3);
-void FUNCTION(igraph_array3, destroy)(TYPE(igraph_array3) *a);
-long int FUNCTION(igraph_array3, size)(const TYPE(igraph_array3) *a);
-long int FUNCTION(igraph_array3, n)(const TYPE(igraph_array3) *a, long int idx);
-int FUNCTION(igraph_array3, resize)(TYPE(igraph_array3) *a, long int n1, long int n2,
+DECLDIR void FUNCTION(igraph_array3, destroy)(TYPE(igraph_array3) *a);
+DECLDIR long int FUNCTION(igraph_array3, size)(const TYPE(igraph_array3) *a);
+DECLDIR long int FUNCTION(igraph_array3, n)(const TYPE(igraph_array3) *a, long int idx);
+DECLDIR int FUNCTION(igraph_array3, resize)(TYPE(igraph_array3) *a, long int n1, long int n2,
                                     long int n3);
-void FUNCTION(igraph_array3, null)(TYPE(igraph_array3) *a);
-BASE FUNCTION(igraph_array3, sum)(const TYPE(igraph_array3) *a);
-void FUNCTION(igraph_array3, scale)(TYPE(igraph_array3) *a, BASE by);
-void FUNCTION(igraph_array3, fill)(TYPE(igraph_array3) *a, BASE e);
-int FUNCTION(igraph_array3, update)(TYPE(igraph_array3) *to,
+DECLDIR void FUNCTION(igraph_array3, null)(TYPE(igraph_array3) *a);
+DECLDIR BASE FUNCTION(igraph_array3, sum)(const TYPE(igraph_array3) *a);
+DECLDIR void FUNCTION(igraph_array3, scale)(TYPE(igraph_array3) *a, BASE by);
+DECLDIR void FUNCTION(igraph_array3, fill)(TYPE(igraph_array3) *a, BASE e);
+DECLDIR int FUNCTION(igraph_array3, update)(TYPE(igraph_array3) *to,
                                     const TYPE(igraph_array3) *from);
diff --git a/igraph/include/igraph_attributes.h b/igraph/include/igraph_attributes.h
--- a/igraph/include/igraph_attributes.h
+++ b/igraph/include/igraph_attributes.h
@@ -21,8 +21,8 @@
 
 */
 
-#ifndef REST_ATTRIBUTES_H
-#define REST_ATTRIBUTES_H
+#ifndef IGRAPH_ATTRIBUTES_H
+#define IGRAPH_ATTRIBUTES_H
 
 #include "igraph_decls.h"
 #include "igraph_datatype.h"
@@ -385,7 +385,7 @@
 
 /* Experimental attribute handler in C */
 
-extern const igraph_attribute_table_t igraph_cattribute_table;
+DECLDIR extern const igraph_attribute_table_t igraph_cattribute_table;
 
 DECLDIR igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name);
 DECLDIR igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name);
@@ -778,7 +778,7 @@
 #define SETVASV(graph,n,v) (igraph_cattribute_VAS_setv((graph),(n),(v)))
 /**
  * \define SETEANV
- *  Set a numeric edge attribute for all vertices
+ *  Set a numeric edge attribute for all edges
  *
  * This is a shorthand for \ref igraph_cattribute_EAN_setv().
  * \param graph The graph.
@@ -788,7 +788,7 @@
 #define SETEANV(graph,n,v) (igraph_cattribute_EAN_setv((graph),(n),(v)))
 /**
  * \define SETEABV
- *  Set a boolean edge attribute for all vertices
+ *  Set a boolean edge attribute for all edges
  *
  * This is a shorthand for \ref igraph_cattribute_EAB_setv().
  * \param graph The graph.
@@ -798,7 +798,7 @@
 #define SETEABV(graph,n,v) (igraph_cattribute_EAB_setv((graph),(n),(v)))
 /**
  * \define SETEASV
- *  Set a string edge attribute for all vertices
+ *  Set a string edge attribute for all edges
  *
  * This is a shorthand for \ref igraph_cattribute_EAS_setv().
  * \param graph The graph.
diff --git a/igraph/include/igraph_blas.h b/igraph/include/igraph_blas.h
--- a/igraph/include/igraph_blas.h
+++ b/igraph/include/igraph_blas.h
@@ -21,8 +21,8 @@
 
 */
 
-#ifndef BLAS_H
-#define BLAS_H
+#ifndef IGRAPH_BLAS_H
+#define IGRAPH_BLAS_H
 
 #include "igraph_types.h"
 #include "igraph_vector.h"
@@ -59,6 +59,9 @@
                                      igraph_real_t beta, igraph_real_t* y);
 
 DECLDIR igraph_real_t igraph_blas_dnrm2(const igraph_vector_t *v);
+
+DECLDIR int igraph_blas_ddot(const igraph_vector_t *v1, const igraph_vector_t *v2,
+                               igraph_real_t *res);
 
 __END_DECLS
 
diff --git a/igraph/include/igraph_blas_internal.h b/igraph/include/igraph_blas_internal.h
--- a/igraph/include/igraph_blas_internal.h
+++ b/igraph/include/igraph_blas_internal.h
@@ -34,13 +34,13 @@
 
 #ifndef INTERNAL_BLAS
     #define igraphdaxpy_    daxpy_
-    #define igraphdger_ dger_
+    #define igraphdger_     dger_
     #define igraphdcopy_    dcopy_
     #define igraphdscal_    dscal_
     #define igraphdswap_    dswap_
     #define igraphdgemm_    dgemm_
     #define igraphdgemv_    dgemv_
-    #define igraphddot_ ddot_
+    #define igraphddot_     ddot_
     #define igraphdnrm2_    dnrm2_
     #define igraphlsame_    lsame_
     #define igraphdrot_     drot_
@@ -50,6 +50,11 @@
     #define igraphdtrsm_    dtrsm_
     #define igraphdtrsv_    dtrsv_
     #define igraphdnrm2_    dnrm2_
+    #define igraphdsymv_    dsymv_
+    #define igraphdsyr2_    dsyr2_
+    #define igraphdsyr2k_   dsyr2k_
+    #define igraphdtrmv_    dtrmv_
+    #define igraphdsyrk_    dsyrk_
 #endif
 
 int igraphdgemv_(char *trans, int *m, int *n, igraph_real_t *alpha,
@@ -61,5 +66,7 @@
                  double *beta, double *c__, int *ldc);
 
 double igraphdnrm2_(int *n, double *x, int *incx);
+
+double igraphddot_(int *n, double *dx, int *incx, double *dy, int *incy);
 
 #endif
diff --git a/igraph/include/igraph_cliques.h b/igraph/include/igraph_cliques.h
--- a/igraph/include/igraph_cliques.h
+++ b/igraph/include/igraph_cliques.h
@@ -83,7 +83,7 @@
 
 /**
  * \typedef igraph_clique_handler_t
- * \brief Type of clique handler functions
+ * \brief Type of clique handler functions.
  *
  * Callback type, called when a clique was found.
  *
diff --git a/igraph/include/igraph_coloring.h b/igraph/include/igraph_coloring.h
--- a/igraph/include/igraph_coloring.h
+++ b/igraph/include/igraph_coloring.h
@@ -1,3 +1,23 @@
+/*
+  Heuristic graph coloring algorithms.
+  Copyright (C) 2017 Szabolcs Horvat <szhorvat@gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
 #ifndef IGRAPH_COLORING_H
 #define IGRAPH_COLORING_H
 
@@ -7,7 +27,9 @@
 
 /**
  * \typedef igraph_coloring_greedy_t
- * Ordering heuristics for igraph_vertex_coloring_greedy
+ * \brief Ordering heuristics for greedy graph coloring.
+ *
+ * Ordering heuristics for \ref igraph_vertex_coloring_greedy().
  *
  * \enumval IGRAPH_COLORING_GREEDY_COLORED_NEIGHBORS  Choose vertex with largest number of already colored neighbors.
  *
diff --git a/igraph/include/igraph_datatype.h b/igraph/include/igraph_datatype.h
--- a/igraph/include/igraph_datatype.h
+++ b/igraph/include/igraph_datatype.h
@@ -57,11 +57,14 @@
  * - <b>is</b> This is basically the same as <b>os</b>, but this time
  *   for the incoming edges.
  *
- * For undirected graph, the same edge list is stored, ie. an
- * undirected edge is stored only once, and for checking whether there
- * is an undirected edge from \c v1 to \c v2 one
- * should search for both \c from=v1, \c to=v2 and
- * \c from=v2, \c to=v1.
+ * For undirected graphs, the same edge list is stored, i.e. an
+ * undirected edge is stored only once. Currently, undirected edges
+ * are canonicalized so that the index of the 'from' vertex is not greater
+ * than the index of the 'to' vertex. Thus, if v1 <= v2, only the edge (v1, v2)
+ * needs to be searched for, not (v2, v1), to determine if v1 and v2 are connected.
+ * However, this fact is NOT guaranteed by the documented public API, 
+ * and should not be relied upon by the implementation of any functions, 
+ * except those belonging to the minimal API in type_indexededgelist.c.
  *
  * The storage requirements for a graph with \c |V| vertices
  * and \c |E| edges is \c O(|E|+|V|).
diff --git a/igraph/include/igraph_decls.h b/igraph/include/igraph_decls.h
--- a/igraph/include/igraph_decls.h
+++ b/igraph/include/igraph_decls.h
@@ -8,18 +8,15 @@
     #define __END_DECLS /* empty */
 #endif
 
+/* In igraph 0.8, we use DECLDIR only with MSVC, not other compilers on Windows. */
 #undef DECLDIR
-#if defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64)
-    #if defined (__MINGW32__) || defined (__CYGWIN32__)
+#if defined (_MSC_VER)
+    #ifdef IGRAPH_EXPORTS
+        #define DECLDIR __declspec(dllexport)
+    #elif defined(IGRAPH_STATIC)
         #define DECLDIR /**/
     #else
-        #ifdef IGRAPH_EXPORTS
-            #define DECLDIR __declspec(dllexport)
-        #elif defined(IGRAPH_STATIC)
-            #define DECLDIR /**/
-        #else
-            #define DECLDIR __declspec(dllimport)
-        #endif
+        #define DECLDIR __declspec(dllimport)
     #endif
 #else
     #define DECLDIR /**/
diff --git a/igraph/include/igraph_dqueue_pmt.h b/igraph/include/igraph_dqueue_pmt.h
--- a/igraph/include/igraph_dqueue_pmt.h
+++ b/igraph/include/igraph_dqueue_pmt.h
@@ -44,6 +44,6 @@
 DECLDIR BASE FUNCTION(igraph_dqueue, head)    (const TYPE(igraph_dqueue)* q);
 DECLDIR BASE FUNCTION(igraph_dqueue, back)    (const TYPE(igraph_dqueue)* q);
 DECLDIR int FUNCTION(igraph_dqueue, push)    (TYPE(igraph_dqueue)* q, BASE elem);
-int FUNCTION(igraph_dqueue, print)(const TYPE(igraph_dqueue)* q);
-int FUNCTION(igraph_dqueue, fprint)(const TYPE(igraph_dqueue)* q, FILE *file);
+DECLDIR int FUNCTION(igraph_dqueue, print)(const TYPE(igraph_dqueue)* q);
+DECLDIR int FUNCTION(igraph_dqueue, fprint)(const TYPE(igraph_dqueue)* q, FILE *file);
 DECLDIR BASE FUNCTION(igraph_dqueue, e)(const TYPE(igraph_dqueue) *q, long int idx);
diff --git a/igraph/include/igraph_error.h b/igraph/include/igraph_error.h
--- a/igraph/include/igraph_error.h
+++ b/igraph/include/igraph_error.h
@@ -112,7 +112,7 @@
  * function of type \ref igraph_error_handler_t and calling
  * \ref igraph_set_error_handler(). This feature is useful for interface
  * writers, as \a igraph will have the chance to
- * signal errors the appropriate way, eg. the R interface defines an
+ * signal errors the appropriate way, e.g. the R interface defines an
  * error handler which calls the <function>error()</function>
  * function, as required by R, while the Python interface has an error
  * handler which raises an exception according to the Python way.
@@ -217,7 +217,7 @@
  * program.
  */
 
-extern igraph_error_handler_t igraph_error_handler_abort;
+DECLDIR igraph_error_handler_t igraph_error_handler_abort;
 
 /**
  * \var igraph_error_handler_ignore
@@ -227,7 +227,7 @@
  * with the error code.
  */
 
-extern igraph_error_handler_t igraph_error_handler_ignore;
+DECLDIR igraph_error_handler_t igraph_error_handler_ignore;
 
 /**
  * \var igraph_error_handler_printignore
@@ -237,7 +237,7 @@
  * standard error and returns with the error code.
  */
 
-extern igraph_error_handler_t igraph_error_handler_printignore;
+DECLDIR igraph_error_handler_t igraph_error_handler_printignore;
 
 /**
  * \function igraph_set_error_handler
@@ -268,7 +268,7 @@
  * \enumval IGRAPH_ENOMEM There wasn't enough memory to allocate
  *    on the heap.
  * \enumval IGRAPH_PARSEERROR A parse error was found in a file.
- * \enumval IGRAPH_EINVAL A parameter's value is invalid. Eg. negative
+ * \enumval IGRAPH_EINVAL A parameter's value is invalid. E.g. negative
  *    number was specified as the number of vertices.
  * \enumval IGRAPH_EXISTS A graph/vertex/edge attribute is already
  *    installed with the given name.
@@ -278,7 +278,7 @@
  * \enumval IGRAPH_NONSQUARE A non-square matrix was received while a
  *    square matrix was expected.
  * \enumval IGRAPH_EINVMODE Invalid mode parameter.
- * \enumval IGRAPH_EFILE A file operation failed. Eg. a file doesn't exist,
+ * \enumval IGRAPH_EFILE A file operation failed. E.g. a file doesn't exist,
  *   or the user has no rights to open it.
  * \enumval IGRAPH_UNIMPLEMENTED Attempted to call an unimplemented or
  *   disabled (at compile-time) function.
@@ -330,8 +330,6 @@
  * \enumval IGRAPH_ERWSTUCK Random walk got stuck.
  */
 
-/* Each enum value below must have a corresponding error string in
- * igraph_i_error_strings[] in igraph_error.c */
 typedef enum {
     IGRAPH_SUCCESS           = 0,
     IGRAPH_FAILURE           = 1,
@@ -394,6 +392,8 @@
     IGRAPH_ERWSTUCK          = 59,
     IGRAPH_STOP              = 60, /* undocumented, used internally; signals a request to stop in functions like igraph_i_maximal_cliques_bk */
 } igraph_error_type_t;
+/* Each enum value above must have a corresponding error string in
+ * igraph_i_error_strings[] in igraph_error.c */
 
 /**
  * \define IGRAPH_ERROR
@@ -408,7 +408,7 @@
  * \ref igraph_error() directly.
  * \param reason Textual description of the error. This should be
  *   something more descriptive than the text associated with the error
- *   code. Eg. if the error code is \c IGRAPH_EINVAL,
+ *   code. E.g. if the error code is \c IGRAPH_EINVAL,
  *   its associated text (see  \ref igraph_strerror()) is "Invalid
  *   value" and this string should explain which parameter was invalid
  *   and maybe why.
@@ -448,7 +448,7 @@
  * \brief Trigger an error, printf-like version.
  *
  * \param reason Textual description of the error, interpreted as
- *               a printf format string.
+ *               a \c printf format string.
  * \param file The source file in which the error was noticed.
  * \param line The line in the source file which triggered the error.
  * \param igraph_errno The \a igraph error code.
@@ -564,7 +564,13 @@
  */
 
 #define IGRAPH_FINALLY(func,ptr) \
-    IGRAPH_FINALLY_REAL((igraph_finally_func_t*)(func), (ptr))
+    { \
+        /* the following branch makes the compiler check the compatibility of \
+         * func and ptr to detect cases when we are accidentally invoking an \
+         * incorrect destructor function with the pointer */ \
+        if (0) { func(ptr); } \
+        IGRAPH_FINALLY_REAL((igraph_finally_func_t*)(func), (ptr)); \
+    }
 
 #if !defined(GCC_VERSION_MAJOR) && defined(__GNUC__)
     #define GCC_VERSION_MAJOR  __GNUC__
@@ -578,6 +584,19 @@
     #define IGRAPH_LIKELY(a)   a
 #endif
 
+#if IGRAPH_VERIFY_FINALLY_STACK == 1
+#define IGRAPH_CHECK(a) \
+        do { \
+            int enter_stack_size = IGRAPH_FINALLY_STACK_SIZE(); \
+            int igraph_i_ret=(a); \
+            if (IGRAPH_UNLIKELY(igraph_i_ret != 0)) {\
+                IGRAPH_ERROR("", igraph_i_ret); \
+            } \
+            if (IGRAPH_UNLIKELY(enter_stack_size != IGRAPH_FINALLY_STACK_SIZE())) { \
+                IGRAPH_ERROR("Non-matching number of IGRAPH_FINALLY and IGRAPH_FINALLY_CLEAN", IGRAPH_FAILURE); \
+            } \
+        } while (0)
+#else
 /**
  * \define IGRAPH_CHECK
  * \brief Check the return value of a function call.
@@ -596,18 +615,19 @@
  * igraph_error_handler_printignore), and the \a igraph function
  * signalling the error is called from another \a igraph function
  * then we need to make sure that the error is propagated back to
- * the auxiliary (ie. non-igraph) calling function. This is achieved
+ * the auxiliary (i.e. non-igraph) calling function. This is achieved
  * by using <function>IGRAPH_CHECK</function> on every \a igraph
  * call which can return an error code.
  */
-
 #define IGRAPH_CHECK(a) do { \
         int igraph_i_ret=(a); \
         if (IGRAPH_UNLIKELY(igraph_i_ret != 0)) {\
             IGRAPH_ERROR("", igraph_i_ret); \
         } } while (0)
+#endif
 
 
+
 /**
  * \section about_igraph_warnings Warning messages
  *
@@ -658,8 +678,8 @@
 
 DECLDIR igraph_warning_handler_t* igraph_set_warning_handler(igraph_warning_handler_t* new_handler);
 
-extern igraph_warning_handler_t igraph_warning_handler_ignore;
-extern igraph_warning_handler_t igraph_warning_handler_print;
+DECLDIR igraph_warning_handler_t igraph_warning_handler_ignore;
+DECLDIR igraph_warning_handler_t igraph_warning_handler_print;
 
 /**
  * \function igraph_warning
diff --git a/igraph/include/igraph_flow.h b/igraph/include/igraph_flow.h
--- a/igraph/include/igraph_flow.h
+++ b/igraph/include/igraph_flow.h
@@ -33,7 +33,7 @@
 __BEGIN_DECLS
 
 /* -------------------------------------------------- */
-/* MAximum flows, minimum cuts & such                 */
+/* Maximum flows, minimum cuts & such                 */
 /* -------------------------------------------------- */
 
 /**
diff --git a/igraph/include/igraph_handle_exceptions.h b/igraph/include/igraph_handle_exceptions.h
new file mode 100644
--- /dev/null
+++ b/igraph/include/igraph_handle_exceptions.h
@@ -0,0 +1,14 @@
+#ifndef IGRAPH_HANDLE_EXCEPTIONS_H
+#define IGRAPH_HANDLE_EXCEPTIONS_H
+
+#include <exception>
+#include <new>
+
+#define IGRAPH_HANDLE_EXCEPTIONS(code) \
+    try { code; } \
+    catch (const std::bad_alloc &e) { IGRAPH_ERROR(e.what(), IGRAPH_ENOMEM); } \
+    catch (const std::exception &e) { IGRAPH_ERROR(e.what(), IGRAPH_FAILURE); } \
+    catch (...) { IGRAPH_ERROR("Unknown exception caught", IGRAPH_FAILURE); }
+
+
+#endif // IGRAPH_HANDLE_EXCEPTIONS_H
diff --git a/igraph/include/igraph_heap_pmt.h b/igraph/include/igraph_heap_pmt.h
--- a/igraph/include/igraph_heap_pmt.h
+++ b/igraph/include/igraph_heap_pmt.h
@@ -37,9 +37,3 @@
 DECLDIR BASE FUNCTION(igraph_heap, delete_top)(TYPE(igraph_heap)* h);
 DECLDIR long int FUNCTION(igraph_heap, size)(TYPE(igraph_heap)* h);
 DECLDIR int FUNCTION(igraph_heap, reserve)(TYPE(igraph_heap)* h, long int size);
-
-void FUNCTION(igraph_heap, i_build)(BASE* arr, long int size, long int head);
-void FUNCTION(igraph_heap, i_shift_up)(BASE* arr, long int size, long int elem);
-void FUNCTION(igraph_heap, i_sink)(BASE* arr, long int size, long int head);
-void FUNCTION(igraph_heap, i_switch)(BASE* arr, long int e1, long int e2);
-
diff --git a/igraph/include/igraph_hrg.h b/igraph/include/igraph_hrg.h
--- a/igraph/include/igraph_hrg.h
+++ b/igraph/include/igraph_hrg.h
@@ -81,6 +81,7 @@
 DECLDIR int igraph_hrg_sample(const igraph_t *graph,
                               igraph_t *sample,
                               igraph_vector_ptr_t *samples,
+                              igraph_integer_t no_samples,
                               igraph_hrg_t *hrg,
                               igraph_bool_t start);
 
diff --git a/igraph/include/igraph_interface.h b/igraph/include/igraph_interface.h
--- a/igraph/include/igraph_interface.h
+++ b/igraph/include/igraph_interface.h
@@ -76,10 +76,49 @@
 DECLDIR int igraph_incident(const igraph_t *graph, igraph_vector_t *eids, igraph_integer_t vid,
                             igraph_neimode_t mode);
 
-#define IGRAPH_FROM(g,e) ((igraph_integer_t)(VECTOR((g)->from)[(long int)(e)]))
-#define IGRAPH_TO(g,e)   ((igraph_integer_t)(VECTOR((g)->to)  [(long int)(e)]))
-#define IGRAPH_OTHER(g,e,v) \
-    ((igraph_integer_t)(IGRAPH_TO(g,(e))==(v) ? IGRAPH_FROM((g),(e)) : IGRAPH_TO((g),(e))))
+/**
+ * \define IGRAPH_FROM
+ * \brief The source vertex of an edge.
+ *
+ * Faster than \ref igraph_edge(), but no error checking is done: \p eid is assumed to be valid.
+ *
+ * \param graph The graph.
+ * \param eid   The edge ID.
+ * \return The source vertex of the edge.
+ * \sa \ref igraph_edge() if error checking is desired.
+ */
+#define IGRAPH_FROM(graph,eid) ((igraph_integer_t)(VECTOR((graph)->from)[(long int)(eid)]))
+
+/**
+ * \define IGRAPH_TO
+ * \brief The target vertex of an edge.
+ *
+ * Faster than \ref igraph_edge(), but no error checking is done: \p eid is assumed to be valid.
+ *
+ * \param graph The graph object.
+ * \param eid   The edge ID.
+ * \return The target vertex of the edge.
+ * \sa \ref igraph_edge() if error checking is desired.
+ */
+#define IGRAPH_TO(graph,eid)   ((igraph_integer_t)(VECTOR((graph)->to)  [(long int)(eid)]))
+
+/**
+ * \define IGRAPH_OTHER
+ * \brief The other endpoint of an edge.
+ *
+ * Typically used with undirected edges when one endpoint of the edge is known,
+ * and the other endpoint is needed. No error checking is done:
+ * \p eid and \p vid are assumed to be valid.
+ *
+ * \param graph The graph object.
+ * \param eid   The edge ID.
+ * \param vid   The vertex ID of one endpoint of an edge.
+ * \return The other endpoint of the edge.
+ * \sa \ref IGRAPH_TO() and \ref IGRAPH_FROM() to get the source and target
+ *     of directed edges.
+ */
+#define IGRAPH_OTHER(graph,eid,vid) \
+    ((igraph_integer_t)(IGRAPH_TO(graph,(eid))==(vid) ? IGRAPH_FROM((graph),(eid)) : IGRAPH_TO((graph),(eid))))
 
 __END_DECLS
 
diff --git a/igraph/include/igraph_isoclasses.h b/igraph/include/igraph_isoclasses.h
new file mode 100644
--- /dev/null
+++ b/igraph/include/igraph_isoclasses.h
@@ -0,0 +1,54 @@
+/* -*- mode: C -*-  */
+/*
+   IGraph library.
+   Copyright (C) 2008-2020  The igraph development team
+   334 Harvard street, Cambridge, MA 02139 USA
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA
+
+*/
+
+#ifndef IGRAPH_ISOCLASSES_H
+#define IGRAPH_ISOCLASSES_H
+
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+    #define __BEGIN_DECLS extern "C" {
+    #define __END_DECLS }
+#else
+    #define __BEGIN_DECLS /* empty */
+    #define __END_DECLS /* empty */
+#endif
+
+__BEGIN_DECLS
+
+extern const unsigned int igraph_i_isoclass_3[];
+extern const unsigned int igraph_i_isoclass_4[];
+extern const unsigned int igraph_i_isoclass_3u[];
+extern const unsigned int igraph_i_isoclass_4u[];
+extern const unsigned int igraph_i_isoclass2_3[];
+extern const unsigned int igraph_i_isoclass2_4[];
+extern const unsigned int igraph_i_isoclass2_3u[];
+extern const unsigned int igraph_i_isoclass2_4u[];
+extern const unsigned int igraph_i_isoclass_3_idx[];
+extern const unsigned int igraph_i_isoclass_4_idx[];
+extern const unsigned int igraph_i_isoclass_3u_idx[];
+extern const unsigned int igraph_i_isoclass_4u_idx[];
+
+__END_DECLS
+
+#endif
diff --git a/igraph/include/igraph_lsap.h b/igraph/include/igraph_lsap.h
--- a/igraph/include/igraph_lsap.h
+++ b/igraph/include/igraph_lsap.h
@@ -1,6 +1,6 @@
 
-#ifndef IGRAPH_LSAP
-#define IGRAPH_LSAP
+#ifndef IGRAPH_LSAP_H
+#define IGRAPH_LSAP_H
 
 #include "igraph_types.h"
 #include "igraph_vector.h"
diff --git a/igraph/include/igraph_matrix.h b/igraph/include/igraph_matrix.h
--- a/igraph/include/igraph_matrix.h
+++ b/igraph/include/igraph_matrix.h
@@ -89,11 +89,11 @@
  */
 #define MATRIX(m,i,j) ((m).data.stor_begin[(m).nrow*(j)+(i)])
 
-igraph_bool_t igraph_matrix_all_e_tol(const igraph_matrix_t *lhs,
+DECLDIR igraph_bool_t igraph_matrix_all_e_tol(const igraph_matrix_t *lhs,
                                       const igraph_matrix_t *rhs,
                                       igraph_real_t tol);
 
-int igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol);
+DECLDIR int igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol);
 
 __END_DECLS
 
diff --git a/igraph/include/igraph_matrix_pmt.h b/igraph/include/igraph_matrix_pmt.h
--- a/igraph/include/igraph_matrix_pmt.h
+++ b/igraph/include/igraph_matrix_pmt.h
@@ -44,7 +44,7 @@
 /* MATRIX */
 DECLDIR BASE FUNCTION(igraph_matrix, e)(const TYPE(igraph_matrix) *m,
                                         long int row, long int col);
-BASE* FUNCTION(igraph_matrix, e_ptr)(const TYPE(igraph_matrix) *m,
+DECLDIR BASE* FUNCTION(igraph_matrix, e_ptr)(const TYPE(igraph_matrix) *m,
                                      long int row, long int col);
 DECLDIR void FUNCTION(igraph_matrix, set)(TYPE(igraph_matrix)* m, long int row, long int col,
         BASE value);
@@ -60,7 +60,7 @@
 /* Matrix views          */
 /*-----------------------*/
 
-const TYPE(igraph_matrix) *FUNCTION(igraph_matrix, view)(const TYPE(igraph_matrix) *m,
+DECLDIR const TYPE(igraph_matrix) *FUNCTION(igraph_matrix, view)(const TYPE(igraph_matrix) *m,
         const BASE *data,
         long int nrow,
         long int ncol);
@@ -207,37 +207,33 @@
 /* Print as text          */
 /*------------------------*/
 
-int FUNCTION(igraph_matrix, print)(const TYPE(igraph_matrix) *m);
-int FUNCTION(igraph_matrix, printf)(const TYPE(igraph_matrix) *m,
+DECLDIR int FUNCTION(igraph_matrix, print)(const TYPE(igraph_matrix) *m);
+DECLDIR int FUNCTION(igraph_matrix, printf)(const TYPE(igraph_matrix) *m,
                                     const char *format);
-int FUNCTION(igraph_matrix, fprint)(const TYPE(igraph_matrix) *m,
+DECLDIR int FUNCTION(igraph_matrix, fprint)(const TYPE(igraph_matrix) *m,
                                     FILE *file);
 
 #ifdef BASE_COMPLEX
 
-int igraph_matrix_complex_real(const igraph_matrix_complex_t *v,
+DECLDIR int igraph_matrix_complex_real(const igraph_matrix_complex_t *v,
                                igraph_matrix_t *real);
-int igraph_matrix_complex_imag(const igraph_matrix_complex_t *v,
+DECLDIR int igraph_matrix_complex_imag(const igraph_matrix_complex_t *v,
                                igraph_matrix_t *imag);
-int igraph_matrix_complex_realimag(const igraph_matrix_complex_t *v,
+DECLDIR int igraph_matrix_complex_realimag(const igraph_matrix_complex_t *v,
                                    igraph_matrix_t *real,
                                    igraph_matrix_t *imag);
-int igraph_matrix_complex_create(igraph_matrix_complex_t *v,
+DECLDIR int igraph_matrix_complex_create(igraph_matrix_complex_t *v,
                                  const igraph_matrix_t *real,
                                  const igraph_matrix_t *imag);
-int igraph_matrix_complex_create_polar(igraph_matrix_complex_t *v,
+DECLDIR int igraph_matrix_complex_create_polar(igraph_matrix_complex_t *v,
                                        const igraph_matrix_t *r,
                                        const igraph_matrix_t *theta);
 
 #endif
 
-/* ----------------------------------------------------------------------------*/
-/* For internal use only, may be removed, rewritten ... */
-/* ----------------------------------------------------------------------------*/
-
-int FUNCTION(igraph_matrix, permdelete_rows)(TYPE(igraph_matrix) *m,
+DECLDIR int FUNCTION(igraph_matrix, permdelete_rows)(TYPE(igraph_matrix) *m,
         long int *index, long int nremove);
-int FUNCTION(igraph_matrix, delete_rows_neg)(TYPE(igraph_matrix) *m,
+DECLDIR int FUNCTION(igraph_matrix, delete_rows_neg)(TYPE(igraph_matrix) *m,
         const igraph_vector_t *neg,
         long int nremove);
 
diff --git a/igraph/include/igraph_memory.h b/igraph/include/igraph_memory.h
--- a/igraph/include/igraph_memory.h
+++ b/igraph/include/igraph_memory.h
@@ -21,8 +21,8 @@
 
 */
 
-#ifndef REST_MEMORY_H
-#define REST_MEMORY_H
+#ifndef IGRAPH_MEMORY_H
+#define IGRAPH_MEMORY_H
 
 #include <stdlib.h>
 #include "igraph_decls.h"
diff --git a/igraph/include/igraph_nongraph.h b/igraph/include/igraph_nongraph.h
--- a/igraph/include/igraph_nongraph.h
+++ b/igraph/include/igraph_nongraph.h
@@ -72,7 +72,6 @@
 
 DECLDIR int igraph_running_mean(const igraph_vector_t *data, igraph_vector_t *res,
                                 igraph_integer_t binwidth);
-DECLDIR int igraph_fisher_yates_shuffle(igraph_vector_t *seq);
 DECLDIR int igraph_random_sample(igraph_vector_t *res, igraph_real_t l, igraph_real_t h,
                                  igraph_integer_t length);
 DECLDIR int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts,
diff --git a/igraph/include/igraph_scg.h b/igraph/include/igraph_scg.h
--- a/igraph/include/igraph_scg.h
+++ b/igraph/include/igraph_scg.h
@@ -48,94 +48,94 @@
                IGRAPH_SCG_DIRECTION_RIGHT = 3
              } igraph_scg_direction_t;
 
-int igraph_scg_grouping(const igraph_matrix_t *V,
-                        igraph_vector_t *groups,
-                        igraph_integer_t nt,
-                        const igraph_vector_t *nt_vec,
-                        igraph_scg_matrix_t mtype,
-                        igraph_scg_algorithm_t algo,
-                        const igraph_vector_t *p,
-                        igraph_integer_t maxiter);
+DECLDIR int igraph_scg_grouping(const igraph_matrix_t *V,
+                                igraph_vector_t *groups,
+                                igraph_integer_t nt,
+                                const igraph_vector_t *nt_vec,
+                                igraph_scg_matrix_t mtype,
+                                igraph_scg_algorithm_t algo,
+                                const igraph_vector_t *p,
+                                igraph_integer_t maxiter);
 
-int igraph_scg_semiprojectors(const igraph_vector_t *groups,
-                              igraph_scg_matrix_t mtype,
-                              igraph_matrix_t *L,
-                              igraph_matrix_t *R,
-                              igraph_sparsemat_t *Lsparse,
-                              igraph_sparsemat_t *Rsparse,
-                              const igraph_vector_t *p,
-                              igraph_scg_norm_t norm);
+DECLDIR int igraph_scg_semiprojectors(const igraph_vector_t *groups,
+                                      igraph_scg_matrix_t mtype,
+                                      igraph_matrix_t *L,
+                                      igraph_matrix_t *R,
+                                      igraph_sparsemat_t *Lsparse,
+                                      igraph_sparsemat_t *Rsparse,
+                                      const igraph_vector_t *p,
+                                      igraph_scg_norm_t norm);
 
-int igraph_scg_norm_eps(const igraph_matrix_t *V,
-                        const igraph_vector_t *groups,
-                        igraph_vector_t *eps,
-                        igraph_scg_matrix_t mtype,
-                        const igraph_vector_t *p,
-                        igraph_scg_norm_t norm);
+DECLDIR int igraph_scg_norm_eps(const igraph_matrix_t *V,
+                                const igraph_vector_t *groups,
+                                igraph_vector_t *eps,
+                                igraph_scg_matrix_t mtype,
+                                const igraph_vector_t *p,
+                                igraph_scg_norm_t norm);
 
-int igraph_scg_adjacency(const igraph_t *graph,
-                         const igraph_matrix_t *matrix,
-                         const igraph_sparsemat_t *sparsemat,
-                         const igraph_vector_t *ev,
-                         igraph_integer_t nt,
-                         const igraph_vector_t *nt_vec,
-                         igraph_scg_algorithm_t algo,
-                         igraph_vector_t *values,
-                         igraph_matrix_t *vectors,
-                         igraph_vector_t *groups,
-                         igraph_bool_t use_arpack,
-                         igraph_integer_t maxiter,
-                         igraph_t *scg_graph,
-                         igraph_matrix_t *scg_matrix,
-                         igraph_sparsemat_t *scg_sparsemat,
-                         igraph_matrix_t *L,
-                         igraph_matrix_t *R,
-                         igraph_sparsemat_t *Lsparse,
-                         igraph_sparsemat_t *Rsparse);
+DECLDIR int igraph_scg_adjacency(const igraph_t *graph,
+                                 const igraph_matrix_t *matrix,
+                                 const igraph_sparsemat_t *sparsemat,
+                                 const igraph_vector_t *ev,
+                                 igraph_integer_t nt,
+                                 const igraph_vector_t *nt_vec,
+                                 igraph_scg_algorithm_t algo,
+                                 igraph_vector_t *values,
+                                 igraph_matrix_t *vectors,
+                                 igraph_vector_t *groups,
+                                 igraph_bool_t use_arpack,
+                                 igraph_integer_t maxiter,
+                                 igraph_t *scg_graph,
+                                 igraph_matrix_t *scg_matrix,
+                                 igraph_sparsemat_t *scg_sparsemat,
+                                 igraph_matrix_t *L,
+                                 igraph_matrix_t *R,
+                                 igraph_sparsemat_t *Lsparse,
+                                 igraph_sparsemat_t *Rsparse);
 
-int igraph_scg_stochastic(const igraph_t *graph,
-                          const igraph_matrix_t *matrix,
-                          const igraph_sparsemat_t *sparsemat,
-                          const igraph_vector_t *ev,
-                          igraph_integer_t nt,
-                          const igraph_vector_t *nt_vec,
-                          igraph_scg_algorithm_t algo,
-                          igraph_scg_norm_t norm,
-                          igraph_vector_complex_t *values,
-                          igraph_matrix_complex_t *vectors,
-                          igraph_vector_t *groups,
-                          igraph_vector_t *p,
-                          igraph_bool_t use_arpack,
-                          igraph_integer_t maxiter,
-                          igraph_t *scg_graph,
-                          igraph_matrix_t *scg_matrix,
-                          igraph_sparsemat_t *scg_sparsemat,
-                          igraph_matrix_t *L,
-                          igraph_matrix_t *R,
-                          igraph_sparsemat_t *Lsparse,
-                          igraph_sparsemat_t *Rsparse);
+DECLDIR int igraph_scg_stochastic(const igraph_t *graph,
+                                  const igraph_matrix_t *matrix,
+                                  const igraph_sparsemat_t *sparsemat,
+                                  const igraph_vector_t *ev,
+                                  igraph_integer_t nt,
+                                  const igraph_vector_t *nt_vec,
+                                  igraph_scg_algorithm_t algo,
+                                  igraph_scg_norm_t norm,
+                                  igraph_vector_complex_t *values,
+                                  igraph_matrix_complex_t *vectors,
+                                  igraph_vector_t *groups,
+                                  igraph_vector_t *p,
+                                  igraph_bool_t use_arpack,
+                                  igraph_integer_t maxiter,
+                                  igraph_t *scg_graph,
+                                  igraph_matrix_t *scg_matrix,
+                                  igraph_sparsemat_t *scg_sparsemat,
+                                  igraph_matrix_t *L,
+                                  igraph_matrix_t *R,
+                                  igraph_sparsemat_t *Lsparse,
+                                  igraph_sparsemat_t *Rsparse);
 
-int igraph_scg_laplacian(const igraph_t *graph,
-                         const igraph_matrix_t *matrix,
-                         const igraph_sparsemat_t *sparsemat,
-                         const igraph_vector_t *ev,
-                         igraph_integer_t nt,
-                         const igraph_vector_t *nt_vec,
-                         igraph_scg_algorithm_t algo,
-                         igraph_scg_norm_t norm,
-                         igraph_scg_direction_t direction,
-                         igraph_vector_complex_t *values,
-                         igraph_matrix_complex_t *vectors,
-                         igraph_vector_t *groups,
-                         igraph_bool_t use_arpack,
-                         igraph_integer_t maxiter,
-                         igraph_t *scg_graph,
-                         igraph_matrix_t *scg_matrix,
-                         igraph_sparsemat_t *scg_sparsemat,
-                         igraph_matrix_t *L,
-                         igraph_matrix_t *R,
-                         igraph_sparsemat_t *Lsparse,
-                         igraph_sparsemat_t *Rsparse);
+DECLDIR int igraph_scg_laplacian(const igraph_t *graph,
+                                 const igraph_matrix_t *matrix,
+                                 const igraph_sparsemat_t *sparsemat,
+                                 const igraph_vector_t *ev,
+                                 igraph_integer_t nt,
+                                 const igraph_vector_t *nt_vec,
+                                 igraph_scg_algorithm_t algo,
+                                 igraph_scg_norm_t norm,
+                                 igraph_scg_direction_t direction,
+                                 igraph_vector_complex_t *values,
+                                 igraph_matrix_complex_t *vectors,
+                                 igraph_vector_t *groups,
+                                 igraph_bool_t use_arpack,
+                                 igraph_integer_t maxiter,
+                                 igraph_t *scg_graph,
+                                 igraph_matrix_t *scg_matrix,
+                                 igraph_sparsemat_t *scg_sparsemat,
+                                 igraph_matrix_t *L,
+                                 igraph_matrix_t *R,
+                                 igraph_sparsemat_t *Lsparse,
+                                 igraph_sparsemat_t *Rsparse);
 
 __END_DECLS
 
diff --git a/igraph/include/igraph_sparsemat.h b/igraph/include/igraph_sparsemat.h
--- a/igraph/include/igraph_sparsemat.h
+++ b/igraph/include/igraph_sparsemat.h
@@ -59,228 +59,226 @@
     int col;
 } igraph_sparsemat_iterator_t;
 
-int igraph_sparsemat_init(igraph_sparsemat_t *A, int rows, int cols, int nzmax);
-int igraph_sparsemat_copy(igraph_sparsemat_t *to,
+DECLDIR int igraph_sparsemat_init(igraph_sparsemat_t *A, int rows, int cols, int nzmax);
+DECLDIR int igraph_sparsemat_copy(igraph_sparsemat_t *to,
                           const igraph_sparsemat_t *from);
-void igraph_sparsemat_destroy(igraph_sparsemat_t *A);
-int igraph_sparsemat_realloc(igraph_sparsemat_t *A, int nzmax);
+DECLDIR void igraph_sparsemat_destroy(igraph_sparsemat_t *A);
+DECLDIR int igraph_sparsemat_realloc(igraph_sparsemat_t *A, int nzmax);
 
-long int igraph_sparsemat_nrow(const igraph_sparsemat_t *A);
-long int igraph_sparsemat_ncol(const igraph_sparsemat_t *B);
-igraph_sparsemat_type_t igraph_sparsemat_type(const igraph_sparsemat_t *A);
-igraph_bool_t igraph_sparsemat_is_triplet(const igraph_sparsemat_t *A);
-igraph_bool_t igraph_sparsemat_is_cc(const igraph_sparsemat_t *A);
+DECLDIR long int igraph_sparsemat_nrow(const igraph_sparsemat_t *A);
+DECLDIR long int igraph_sparsemat_ncol(const igraph_sparsemat_t *B);
+DECLDIR igraph_sparsemat_type_t igraph_sparsemat_type(const igraph_sparsemat_t *A);
+DECLDIR igraph_bool_t igraph_sparsemat_is_triplet(const igraph_sparsemat_t *A);
+DECLDIR igraph_bool_t igraph_sparsemat_is_cc(const igraph_sparsemat_t *A);
 
-int igraph_sparsemat_permute(const igraph_sparsemat_t *A,
-                             const igraph_vector_int_t *p,
-                             const igraph_vector_int_t *q,
-                             igraph_sparsemat_t *res);
+DECLDIR int igraph_sparsemat_permute(const igraph_sparsemat_t *A,
+                                     const igraph_vector_int_t *p,
+                                     const igraph_vector_int_t *q,
+                                     igraph_sparsemat_t *res);
 
-int igraph_sparsemat_index(const igraph_sparsemat_t *A,
-                           const igraph_vector_int_t *p,
-                           const igraph_vector_int_t *q,
-                           igraph_sparsemat_t *res,
-                           igraph_real_t *constres);
+DECLDIR int igraph_sparsemat_index(const igraph_sparsemat_t *A,
+                                   const igraph_vector_int_t *p,
+                                   const igraph_vector_int_t *q,
+                                   igraph_sparsemat_t *res,
+                                   igraph_real_t *constres);
 
-int igraph_sparsemat_entry(igraph_sparsemat_t *A, int row, int col,
-                           igraph_real_t elem);
-int igraph_sparsemat_compress(const igraph_sparsemat_t *A,
-                              igraph_sparsemat_t *res);
-int igraph_sparsemat_transpose(const igraph_sparsemat_t *A,
-                               igraph_sparsemat_t *res, int values);
-igraph_bool_t igraph_sparsemat_is_symmetric(const igraph_sparsemat_t *A);
-int igraph_sparsemat_dupl(igraph_sparsemat_t *A);
-int igraph_sparsemat_fkeep(igraph_sparsemat_t *A,
-                           int (*fkeep)(int, int, igraph_real_t, void*),
-                           void *other);
-int igraph_sparsemat_dropzeros(igraph_sparsemat_t *A);
-int igraph_sparsemat_droptol(igraph_sparsemat_t *A, igraph_real_t tol);
-int igraph_sparsemat_multiply(const igraph_sparsemat_t *A,
-                              const igraph_sparsemat_t *B,
-                              igraph_sparsemat_t *res);
-int igraph_sparsemat_add(const igraph_sparsemat_t *A,
-                         const igraph_sparsemat_t *B,
-                         igraph_real_t alpha,
-                         igraph_real_t beta,
-                         igraph_sparsemat_t *res);
-int igraph_sparsemat_gaxpy(const igraph_sparsemat_t *A,
-                           const igraph_vector_t *x,
-                           igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_entry(igraph_sparsemat_t *A, int row, int col,
+                                   igraph_real_t elem);
+DECLDIR int igraph_sparsemat_compress(const igraph_sparsemat_t *A,
+                                      igraph_sparsemat_t *res);
+DECLDIR int igraph_sparsemat_transpose(const igraph_sparsemat_t *A,
+                                       igraph_sparsemat_t *res, int values);
+DECLDIR igraph_bool_t igraph_sparsemat_is_symmetric(const igraph_sparsemat_t *A);
+DECLDIR int igraph_sparsemat_dupl(igraph_sparsemat_t *A);
+DECLDIR int igraph_sparsemat_fkeep(igraph_sparsemat_t *A,
+                                   int (*fkeep)(int, int, igraph_real_t, void*),
+                                   void *other);
+DECLDIR int igraph_sparsemat_dropzeros(igraph_sparsemat_t *A);
+DECLDIR int igraph_sparsemat_droptol(igraph_sparsemat_t *A, igraph_real_t tol);
+DECLDIR int igraph_sparsemat_multiply(const igraph_sparsemat_t *A,
+                                      const igraph_sparsemat_t *B,
+                                      igraph_sparsemat_t *res);
+DECLDIR int igraph_sparsemat_add(const igraph_sparsemat_t *A,
+                                 const igraph_sparsemat_t *B,
+                                 igraph_real_t alpha,
+                                 igraph_real_t beta,
+                                 igraph_sparsemat_t *res);
+DECLDIR int igraph_sparsemat_gaxpy(const igraph_sparsemat_t *A,
+                                   const igraph_vector_t *x,
+                                   igraph_vector_t *res);
 
-int igraph_sparsemat_lsolve(const igraph_sparsemat_t *A,
-                            const igraph_vector_t *b,
-                            igraph_vector_t *res);
-int igraph_sparsemat_ltsolve(const igraph_sparsemat_t *A,
-                             const igraph_vector_t *b,
-                             igraph_vector_t *res);
-int igraph_sparsemat_usolve(const igraph_sparsemat_t *A,
-                            const igraph_vector_t *b,
-                            igraph_vector_t *res);
-int igraph_sparsemat_utsolve(const igraph_sparsemat_t *A,
-                             const igraph_vector_t *b,
-                             igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_lsolve(const igraph_sparsemat_t *A,
+                                    const igraph_vector_t *b,
+                                    igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_ltsolve(const igraph_sparsemat_t *A,
+                                     const igraph_vector_t *b,
+                                     igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_usolve(const igraph_sparsemat_t *A,
+                                    const igraph_vector_t *b,
+                                    igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_utsolve(const igraph_sparsemat_t *A,
+                                     const igraph_vector_t *b,
+                                     igraph_vector_t *res);
 
-int igraph_sparsemat_cholsol(const igraph_sparsemat_t *A,
-                             const igraph_vector_t *b,
-                             igraph_vector_t *res,
-                             int order);
+DECLDIR int igraph_sparsemat_cholsol(const igraph_sparsemat_t *A,
+                                     const igraph_vector_t *b,
+                                     igraph_vector_t *res,
+                                     int order);
 
-int igraph_sparsemat_lusol(const igraph_sparsemat_t *A,
-                           const igraph_vector_t *b,
-                           igraph_vector_t *res,
-                           int order,
-                           igraph_real_t tol);
+DECLDIR int igraph_sparsemat_lusol(const igraph_sparsemat_t *A,
+                                   const igraph_vector_t *b,
+                                   igraph_vector_t *res,
+                                   int order,
+                                   igraph_real_t tol);
 
-int igraph_sparsemat_print(const igraph_sparsemat_t *A,
-                           FILE *outstream);
+DECLDIR int igraph_sparsemat_print(const igraph_sparsemat_t *A,
+                                   FILE *outstream);
 
-int igraph_sparsemat_eye(igraph_sparsemat_t *A, int n, int nzmax,
-                         igraph_real_t value,
-                         igraph_bool_t compress);
+DECLDIR int igraph_sparsemat_eye(igraph_sparsemat_t *A, int n, int nzmax,
+                                 igraph_real_t value,
+                                 igraph_bool_t compress);
 
-int igraph_sparsemat_diag(igraph_sparsemat_t *A, int nzmax,
-                          const igraph_vector_t *values,
-                          igraph_bool_t compress);
+DECLDIR int igraph_sparsemat_diag(igraph_sparsemat_t *A, int nzmax,
+                                  const igraph_vector_t *values,
+                                  igraph_bool_t compress);
 
-int igraph_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A,
-                     igraph_bool_t directed);
+DECLDIR int igraph_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A,
+                             igraph_bool_t directed);
 
-int igraph_weighted_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A,
-                              igraph_bool_t directed, const char *attr,
-                              igraph_bool_t loops);
+DECLDIR int igraph_weighted_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A,
+                                      igraph_bool_t directed, const char *attr,
+                                      igraph_bool_t loops);
 
-int igraph_get_sparsemat(const igraph_t *graph, igraph_sparsemat_t *res);
+DECLDIR int igraph_get_sparsemat(const igraph_t *graph, igraph_sparsemat_t *res);
 
-int igraph_matrix_as_sparsemat(igraph_sparsemat_t *res,
-                               const igraph_matrix_t *mat,
-                               igraph_real_t tol);
+DECLDIR int igraph_matrix_as_sparsemat(igraph_sparsemat_t *res,
+                                       const igraph_matrix_t *mat,
+                                       igraph_real_t tol);
 
-int igraph_sparsemat_as_matrix(igraph_matrix_t *res,
-                               const igraph_sparsemat_t *spmat);
+DECLDIR int igraph_sparsemat_as_matrix(igraph_matrix_t *res,
+                                       const igraph_sparsemat_t *spmat);
 
 typedef enum { IGRAPH_SPARSEMAT_SOLVE_LU,
                IGRAPH_SPARSEMAT_SOLVE_QR
              } igraph_sparsemat_solve_t;
 
-int igraph_sparsemat_arpack_rssolve(const igraph_sparsemat_t *A,
-                                    igraph_arpack_options_t *options,
-                                    igraph_arpack_storage_t *storage,
-                                    igraph_vector_t *values,
-                                    igraph_matrix_t *vectors,
-                                    igraph_sparsemat_solve_t solvemethod);
+DECLDIR int igraph_sparsemat_arpack_rssolve(const igraph_sparsemat_t *A,
+                                            igraph_arpack_options_t *options,
+                                            igraph_arpack_storage_t *storage,
+                                            igraph_vector_t *values,
+                                            igraph_matrix_t *vectors,
+                                            igraph_sparsemat_solve_t solvemethod);
 
-int igraph_sparsemat_arpack_rnsolve(const igraph_sparsemat_t *A,
-                                    igraph_arpack_options_t *options,
-                                    igraph_arpack_storage_t *storage,
-                                    igraph_matrix_t *values,
-                                    igraph_matrix_t *vectors);
+DECLDIR int igraph_sparsemat_arpack_rnsolve(const igraph_sparsemat_t *A,
+                                            igraph_arpack_options_t *options,
+                                            igraph_arpack_storage_t *storage,
+                                            igraph_matrix_t *values,
+                                            igraph_matrix_t *vectors);
 
-int igraph_sparsemat_lu(const igraph_sparsemat_t *A,
-                        const igraph_sparsemat_symbolic_t *dis,
-                        igraph_sparsemat_numeric_t *din, double tol);
+DECLDIR int igraph_sparsemat_lu(const igraph_sparsemat_t *A,
+                                const igraph_sparsemat_symbolic_t *dis,
+                                igraph_sparsemat_numeric_t *din, double tol);
 
-int igraph_sparsemat_qr(const igraph_sparsemat_t *A,
-                        const igraph_sparsemat_symbolic_t *dis,
-                        igraph_sparsemat_numeric_t *din);
+DECLDIR int igraph_sparsemat_qr(const igraph_sparsemat_t *A,
+                                const igraph_sparsemat_symbolic_t *dis,
+                                igraph_sparsemat_numeric_t *din);
 
-int igraph_sparsemat_luresol(const igraph_sparsemat_symbolic_t *dis,
-                             const igraph_sparsemat_numeric_t *din,
-                             const igraph_vector_t *b,
-                             igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_luresol(const igraph_sparsemat_symbolic_t *dis,
+                                     const igraph_sparsemat_numeric_t *din,
+                                     const igraph_vector_t *b,
+                                     igraph_vector_t *res);
 
-int igraph_sparsemat_qrresol(const igraph_sparsemat_symbolic_t *dis,
-                             const igraph_sparsemat_numeric_t *din,
-                             const igraph_vector_t *b,
-                             igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_qrresol(const igraph_sparsemat_symbolic_t *dis,
+                                     const igraph_sparsemat_numeric_t *din,
+                                     const igraph_vector_t *b,
+                                     igraph_vector_t *res);
 
-int igraph_sparsemat_symbqr(long int order, const igraph_sparsemat_t *A,
-                            igraph_sparsemat_symbolic_t *dis);
+DECLDIR int igraph_sparsemat_symbqr(long int order, const igraph_sparsemat_t *A,
+                                    igraph_sparsemat_symbolic_t *dis);
 
-int igraph_sparsemat_symblu(long int order, const igraph_sparsemat_t *A,
-                            igraph_sparsemat_symbolic_t *dis);
+DECLDIR int igraph_sparsemat_symblu(long int order, const igraph_sparsemat_t *A,
+                                    igraph_sparsemat_symbolic_t *dis);
 
 
-void igraph_sparsemat_symbolic_destroy(igraph_sparsemat_symbolic_t *dis);
-void igraph_sparsemat_numeric_destroy(igraph_sparsemat_numeric_t *din);
+DECLDIR void igraph_sparsemat_symbolic_destroy(igraph_sparsemat_symbolic_t *dis);
+DECLDIR void igraph_sparsemat_numeric_destroy(igraph_sparsemat_numeric_t *din);
 
-igraph_real_t igraph_sparsemat_max(igraph_sparsemat_t *A);
-igraph_real_t igraph_sparsemat_min(igraph_sparsemat_t *A);
-int igraph_sparsemat_minmax(igraph_sparsemat_t *A,
-                            igraph_real_t *min, igraph_real_t *max);
+DECLDIR igraph_real_t igraph_sparsemat_max(igraph_sparsemat_t *A);
+DECLDIR igraph_real_t igraph_sparsemat_min(igraph_sparsemat_t *A);
+DECLDIR int igraph_sparsemat_minmax(igraph_sparsemat_t *A,
+                                    igraph_real_t *min, igraph_real_t *max);
 
-long int igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A);
-long int igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A,
-        igraph_real_t tol);
-int igraph_sparsemat_rowsums(const igraph_sparsemat_t *A,
-                             igraph_vector_t *res);
-int igraph_sparsemat_colsums(const igraph_sparsemat_t *A,
-                             igraph_vector_t *res);
+DECLDIR long int igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A);
+DECLDIR long int igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A,
+                                                   igraph_real_t tol);
+DECLDIR int igraph_sparsemat_rowsums(const igraph_sparsemat_t *A,
+                                     igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_colsums(const igraph_sparsemat_t *A,
+                                     igraph_vector_t *res);
 
-int igraph_sparsemat_rowmins(igraph_sparsemat_t *A,
-                             igraph_vector_t *res);
-int igraph_sparsemat_colmins(igraph_sparsemat_t *A,
-                             igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_rowmins(igraph_sparsemat_t *A,
+                                     igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_colmins(igraph_sparsemat_t *A,
+                                     igraph_vector_t *res);
 
-int igraph_sparsemat_rowmaxs(igraph_sparsemat_t *A,
-                             igraph_vector_t *res);
-int igraph_sparsemat_colmaxs(igraph_sparsemat_t *A,
-                             igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_rowmaxs(igraph_sparsemat_t *A,
+                                     igraph_vector_t *res);
+DECLDIR int igraph_sparsemat_colmaxs(igraph_sparsemat_t *A,
+                                     igraph_vector_t *res);
 
-int igraph_sparsemat_which_min_rows(igraph_sparsemat_t *A,
-                                    igraph_vector_t *res,
-                                    igraph_vector_int_t *pos);
-int igraph_sparsemat_which_min_cols(igraph_sparsemat_t *A,
-                                    igraph_vector_t *res,
-                                    igraph_vector_int_t *pos);
+DECLDIR int igraph_sparsemat_which_min_rows(igraph_sparsemat_t *A,
+                                            igraph_vector_t *res,
+                                            igraph_vector_int_t *pos);
+DECLDIR int igraph_sparsemat_which_min_cols(igraph_sparsemat_t *A,
+                                            igraph_vector_t *res,
+                                            igraph_vector_int_t *pos);
 
-int igraph_sparsemat_scale(igraph_sparsemat_t *A, igraph_real_t by);
+DECLDIR int igraph_sparsemat_scale(igraph_sparsemat_t *A, igraph_real_t by);
 
 
-int igraph_sparsemat_add_rows(igraph_sparsemat_t *A, long int n);
-int igraph_sparsemat_add_cols(igraph_sparsemat_t *A, long int n);
-int igraph_sparsemat_resize(igraph_sparsemat_t *A, long int nrow,
-                            long int ncol, int nzmax);
-int igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A);
-int igraph_sparsemat_getelements(const igraph_sparsemat_t *A,
-                                 igraph_vector_int_t *i,
-                                 igraph_vector_int_t *j,
-                                 igraph_vector_t *x);
-int igraph_sparsemat_getelements_sorted(const igraph_sparsemat_t *A,
-                                        igraph_vector_int_t *i,
-                                        igraph_vector_int_t *j,
-                                        igraph_vector_t *x);
-int igraph_sparsemat_scale_rows(igraph_sparsemat_t *A,
-                                const igraph_vector_t *fact);
-int igraph_sparsemat_scale_cols(igraph_sparsemat_t *A,
-                                const igraph_vector_t *fact);
-int igraph_sparsemat_multiply_by_dense(const igraph_sparsemat_t *A,
-                                       const igraph_matrix_t *B,
-                                       igraph_matrix_t *res);
-int igraph_sparsemat_dense_multiply(const igraph_matrix_t *A,
-                                    const igraph_sparsemat_t *B,
-                                    igraph_matrix_t *res);
+DECLDIR int igraph_sparsemat_add_rows(igraph_sparsemat_t *A, long int n);
+DECLDIR int igraph_sparsemat_add_cols(igraph_sparsemat_t *A, long int n);
+DECLDIR int igraph_sparsemat_resize(igraph_sparsemat_t *A, long int nrow,
+                                    long int ncol, int nzmax);
+DECLDIR int igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A);
+DECLDIR int igraph_sparsemat_getelements(const igraph_sparsemat_t *A,
+                                         igraph_vector_int_t *i,
+                                         igraph_vector_int_t *j,
+                                         igraph_vector_t *x);
+DECLDIR int igraph_sparsemat_getelements_sorted(const igraph_sparsemat_t *A,
+                                                igraph_vector_int_t *i,
+                                                igraph_vector_int_t *j,
+                                                igraph_vector_t *x);
+DECLDIR int igraph_sparsemat_scale_rows(igraph_sparsemat_t *A,
+                                        const igraph_vector_t *fact);
+DECLDIR int igraph_sparsemat_scale_cols(igraph_sparsemat_t *A,
+                                        const igraph_vector_t *fact);
+DECLDIR int igraph_sparsemat_multiply_by_dense(const igraph_sparsemat_t *A,
+                                               const igraph_matrix_t *B,
+                                               igraph_matrix_t *res);
+DECLDIR int igraph_sparsemat_dense_multiply(const igraph_matrix_t *A,
+                                            const igraph_sparsemat_t *B,
+                                            igraph_matrix_t *res);
 
-int igraph_i_sparsemat_view(igraph_sparsemat_t *A, int nzmax, int m, int n,
-                            int *p, int *i, double *x, int nz);
+DECLDIR int igraph_i_sparsemat_view(igraph_sparsemat_t *A, int nzmax, int m, int n,
+                                    int *p, int *i, double *x, int nz);
 
-int igraph_sparsemat_sort(const igraph_sparsemat_t *A,
-                          igraph_sparsemat_t *sorted);
+DECLDIR int igraph_sparsemat_sort(const igraph_sparsemat_t *A,
+                                  igraph_sparsemat_t *sorted);
 
-int igraph_sparsemat_nzmax(const igraph_sparsemat_t *A);
+DECLDIR int igraph_sparsemat_nzmax(const igraph_sparsemat_t *A);
 
-int igraph_sparsemat_neg(igraph_sparsemat_t *A);
+DECLDIR int igraph_sparsemat_neg(igraph_sparsemat_t *A);
 
-int igraph_sparsemat_iterator_init(igraph_sparsemat_iterator_t *it,
-                                   igraph_sparsemat_t *sparsemat);
-int igraph_sparsemat_iterator_reset(igraph_sparsemat_iterator_t *it);
-igraph_bool_t
-igraph_sparsemat_iterator_end(const igraph_sparsemat_iterator_t *it);
-int igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it);
-int igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it);
-int igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it);
-igraph_real_t
-igraph_sparsemat_iterator_get(const igraph_sparsemat_iterator_t *it);
-int igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it);
+DECLDIR int igraph_sparsemat_iterator_init(igraph_sparsemat_iterator_t *it,
+                                           igraph_sparsemat_t *sparsemat);
+DECLDIR int igraph_sparsemat_iterator_reset(igraph_sparsemat_iterator_t *it);
+DECLDIR igraph_bool_t igraph_sparsemat_iterator_end(const igraph_sparsemat_iterator_t *it);
+DECLDIR int igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it);
+DECLDIR int igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it);
+DECLDIR int igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it);
+DECLDIR igraph_real_t igraph_sparsemat_iterator_get(const igraph_sparsemat_iterator_t *it);
+DECLDIR int igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it);
 
 __END_DECLS
 
diff --git a/igraph/include/igraph_statusbar.h b/igraph/include/igraph_statusbar.h
--- a/igraph/include/igraph_statusbar.h
+++ b/igraph/include/igraph_statusbar.h
@@ -21,8 +21,8 @@
 
 */
 
-#ifndef IGRAPH_STATUSBAR
-#define IGRAPH_STATUSBAR
+#ifndef IGRAPH_STATUSBAR_H
+#define IGRAPH_STATUSBAR_H
 
 #include "igraph_decls.h"
 
diff --git a/igraph/include/igraph_strvector.h b/igraph/include/igraph_strvector.h
--- a/igraph/include/igraph_strvector.h
+++ b/igraph/include/igraph_strvector.h
@@ -57,7 +57,7 @@
 #define IGRAPH_STRVECTOR_NULL { 0,0 }
 #define IGRAPH_STRVECTOR_INIT_FINALLY(v, size) \
     do { IGRAPH_CHECK(igraph_strvector_init(v, size)); \
-        IGRAPH_FINALLY( (igraph_finally_func_t*) igraph_strvector_destroy, v); } while (0)
+        IGRAPH_FINALLY( igraph_strvector_destroy, v); } while (0)
 
 DECLDIR int igraph_strvector_init(igraph_strvector_t *sv, long int len);
 DECLDIR void igraph_strvector_destroy(igraph_strvector_t *sv);
diff --git a/igraph/include/igraph_types.h b/igraph/include/igraph_types.h
--- a/igraph/include/igraph_types.h
+++ b/igraph/include/igraph_types.h
@@ -21,8 +21,8 @@
 
 */
 
-#ifndef REST_TYPES_H
-#define REST_TYPES_H
+#ifndef IGRAPH_TYPES_H
+#define IGRAPH_TYPES_H
 
 #include "igraph_decls.h"
 
diff --git a/igraph/include/igraph_vector.h b/igraph/include/igraph_vector.h
--- a/igraph/include/igraph_vector.h
+++ b/igraph/include/igraph_vector.h
@@ -28,14 +28,6 @@
 #include "igraph_types.h"
 #include "igraph_complex.h"
 
-#ifdef HAVE_STDINT_H
-    #include <stdint.h>
-#else
-    #if defined(HAVE_SYS_INT_TYPES_H) && HAVE_SYS_INT_TYPES_H
-        #include <sys/int_types.h>    /* for Solaris */
-    #endif
-#endif
-
 __BEGIN_DECLS
 
 /* -------------------------------------------------- */
@@ -144,6 +136,11 @@
     do { IGRAPH_CHECK(igraph_vector_bool_init(v, size)); \
         IGRAPH_FINALLY(igraph_vector_bool_destroy, v); } while (0)
 #endif
+#ifndef IGRAPH_VECTOR_CHAR_INIT_FINALLY
+#define IGRAPH_VECTOR_CHAR_INIT_FINALLY(v, size) \
+  do { IGRAPH_CHECK(igraph_vector_char_init(v, size)); \
+  IGRAPH_FINALLY(igraph_vector_char_destroy, v); } while (0)
+#endif
 #ifndef IGRAPH_VECTOR_INT_INIT_FINALLY
 #define IGRAPH_VECTOR_INT_INIT_FINALLY(v, size) \
     do { IGRAPH_CHECK(igraph_vector_int_init(v, size)); \
@@ -168,15 +165,14 @@
 
 DECLDIR int igraph_vector_zapsmall(igraph_vector_t *v, igraph_real_t tol);
 
-/* These are for internal use only */
-int igraph_vector_order(const igraph_vector_t* v, const igraph_vector_t *v2,
+DECLDIR int igraph_vector_order(const igraph_vector_t* v, const igraph_vector_t *v2,
                         igraph_vector_t* res, igraph_real_t maxval);
-int igraph_vector_order1(const igraph_vector_t* v,
+DECLDIR int igraph_vector_order1(const igraph_vector_t* v,
                          igraph_vector_t* res, igraph_real_t maxval);
-int igraph_vector_order1_int(const igraph_vector_t* v,
+DECLDIR int igraph_vector_order1_int(const igraph_vector_t* v,
                              igraph_vector_int_t* res, igraph_real_t maxval);
-int igraph_vector_order2(igraph_vector_t *v);
-int igraph_vector_rank(const igraph_vector_t *v, igraph_vector_t *res,
+DECLDIR int igraph_vector_order2(igraph_vector_t *v);
+DECLDIR int igraph_vector_rank(const igraph_vector_t *v, igraph_vector_t *res,
                        long int nodes);
 
 __END_DECLS
diff --git a/igraph/include/igraph_vector_pmt.h b/igraph/include/igraph_vector_pmt.h
--- a/igraph/include/igraph_vector_pmt.h
+++ b/igraph/include/igraph_vector_pmt.h
@@ -40,29 +40,29 @@
 /*--------------------*/
 
 #ifndef VECTOR
-    /**
-    * \ingroup vector
-    * \define VECTOR
-    * \brief Accessing an element of a vector.
-    *
-    * Usage:
-    * \verbatim VECTOR(v)[0] \endverbatim
-    * to access the first element of the vector, you can also use this in
-    * assignments, like:
-    * \verbatim VECTOR(v)[10]=5; \endverbatim
-    *
-    * Note that there are no range checks right now.
-    * This functionality might be redefined later as a real function
-    * instead of a <code>#define</code>.
-    * \param v The vector object.
-    *
-    * Time complexity: O(1).
-    */
-    #define VECTOR(v) ((v).stor_begin)
+/**
+ * \ingroup vector
+ * \define VECTOR
+ * \brief Accessing an element of a vector.
+ *
+ * Usage:
+ * \verbatim VECTOR(v)[0] \endverbatim
+ * to access the first element of the vector, you can also use this in
+ * assignments, like:
+ * \verbatim VECTOR(v)[10]=5; \endverbatim
+ *
+ * Note that there are no range checks right now.
+ * This functionality might be redefined later as a real function
+ * instead of a <code>#define</code>.
+ * \param v The vector object.
+ *
+ * Time complexity: O(1).
+ */
+#define VECTOR(v) ((v).stor_begin)
 #endif
 
 DECLDIR BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector)* v, long int pos);
-BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector)* v, long int pos);
+DECLDIR BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector)* v, long int pos);
 DECLDIR void FUNCTION(igraph_vector, set)(TYPE(igraph_vector)* v, long int pos, BASE value);
 DECLDIR BASE FUNCTION(igraph_vector, tail)(const TYPE(igraph_vector) *v);
 
@@ -177,6 +177,9 @@
 DECLDIR igraph_bool_t FUNCTION(igraph_vector, search)(const TYPE(igraph_vector) *v,
         long int from, BASE what,
         long int *pos);
+DECLDIR igraph_bool_t FUNCTION(igraph_vector, binsearch_slice)(const TYPE(igraph_vector) *v,
+        BASE what, long int *pos,
+        long int start, long int end);
 DECLDIR igraph_bool_t FUNCTION(igraph_vector, binsearch)(const TYPE(igraph_vector) *v,
         BASE what, long int *pos);
 DECLDIR igraph_bool_t FUNCTION(igraph_vector, binsearch2)(const TYPE(igraph_vector) *v,
@@ -202,6 +205,7 @@
 /*-----------*/
 
 DECLDIR void FUNCTION(igraph_vector, sort)(TYPE(igraph_vector) *v);
+DECLDIR void FUNCTION(igraph_vector, reverse_sort)(TYPE(igraph_vector) *v);
 DECLDIR long int FUNCTION(igraph_vector, qsort_ind)(TYPE(igraph_vector) *v,
         igraph_vector_t *inds, igraph_bool_t descending);
 
@@ -209,10 +213,10 @@
 /* Printing  */
 /*-----------*/
 
-int FUNCTION(igraph_vector, print)(const TYPE(igraph_vector) *v);
-int FUNCTION(igraph_vector, printf)(const TYPE(igraph_vector) *v,
+DECLDIR int FUNCTION(igraph_vector, print)(const TYPE(igraph_vector) *v);
+DECLDIR int FUNCTION(igraph_vector, printf)(const TYPE(igraph_vector) *v,
                                     const char *format);
-int FUNCTION(igraph_vector, fprint)(const TYPE(igraph_vector) *v, FILE *file);
+DECLDIR int FUNCTION(igraph_vector, fprint)(const TYPE(igraph_vector) *v, FILE *file);
 
 #ifdef BASE_COMPLEX
 
@@ -232,34 +236,30 @@
 
 #endif
 
-/* ----------------------------------------------------------------------------*/
-/* For internal use only, may be removed, rewritten ... */
-/* ----------------------------------------------------------------------------*/
-
-int FUNCTION(igraph_vector, init_real)(TYPE(igraph_vector)*v, int no, ...);
-int FUNCTION(igraph_vector, init_int)(TYPE(igraph_vector)*v, int no, ...);
-int FUNCTION(igraph_vector, init_real_end)(TYPE(igraph_vector)*v, BASE endmark, ...);
-int FUNCTION(igraph_vector, init_int_end)(TYPE(igraph_vector)*v, int endmark, ...);
+DECLDIR int FUNCTION(igraph_vector, init_real)(TYPE(igraph_vector)*v, int no, ...);
+DECLDIR int FUNCTION(igraph_vector, init_int)(TYPE(igraph_vector)*v, int no, ...);
+DECLDIR int FUNCTION(igraph_vector, init_real_end)(TYPE(igraph_vector)*v, BASE endmark, ...);
+DECLDIR int FUNCTION(igraph_vector, init_int_end)(TYPE(igraph_vector)*v, int endmark, ...);
 
-int FUNCTION(igraph_vector, move_interval)(TYPE(igraph_vector) *v,
+DECLDIR int FUNCTION(igraph_vector, move_interval)(TYPE(igraph_vector) *v,
         long int begin, long int end, long int to);
-int FUNCTION(igraph_vector, move_interval2)(TYPE(igraph_vector) *v,
+DECLDIR int FUNCTION(igraph_vector, move_interval2)(TYPE(igraph_vector) *v,
         long int begin, long int end, long int to);
-void FUNCTION(igraph_vector, permdelete)(TYPE(igraph_vector) *v,
+DECLDIR void FUNCTION(igraph_vector, permdelete)(TYPE(igraph_vector) *v,
         const igraph_vector_t *index,
         long int nremove);
-int FUNCTION(igraph_vector, filter_smaller)(TYPE(igraph_vector) *v, BASE elem);
-int FUNCTION(igraph_vector, get_interval)(const TYPE(igraph_vector) *v,
+DECLDIR int FUNCTION(igraph_vector, filter_smaller)(TYPE(igraph_vector) *v, BASE elem);
+DECLDIR int FUNCTION(igraph_vector, get_interval)(const TYPE(igraph_vector) *v,
         TYPE(igraph_vector) *res,
         long int from, long int to);
-int FUNCTION(igraph_vector, difference_sorted)(const TYPE(igraph_vector) *v1,
+DECLDIR int FUNCTION(igraph_vector, difference_sorted)(const TYPE(igraph_vector) *v1,
         const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result);
-int FUNCTION(igraph_vector, intersect_sorted)(const TYPE(igraph_vector) *v1,
+DECLDIR int FUNCTION(igraph_vector, intersect_sorted)(const TYPE(igraph_vector) *v1,
         const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result);
 
-int FUNCTION(igraph_vector, index)(const TYPE(igraph_vector) *v,
+DECLDIR int FUNCTION(igraph_vector, index)(const TYPE(igraph_vector) *v,
                                    TYPE(igraph_vector) *newv,
                                    const igraph_vector_t *idx);
 
-int FUNCTION(igraph_vector, index_int)(TYPE(igraph_vector) *v,
+DECLDIR int FUNCTION(igraph_vector, index_int)(TYPE(igraph_vector) *v,
                                        const igraph_vector_int_t *idx);
diff --git a/igraph/include/igraph_version.h b/igraph/include/igraph_version.h
--- a/igraph/include/igraph_version.h
+++ b/igraph/include/igraph_version.h
@@ -28,13 +28,13 @@
 
 __BEGIN_DECLS
 
-#define IGRAPH_VERSION "0.8.0"
+#define IGRAPH_VERSION "0.8.5"
 #define IGRAPH_VERSION_MAJOR 0
 #define IGRAPH_VERSION_MINOR 8
-#define IGRAPH_VERSION_PATCH 0
+#define IGRAPH_VERSION_PATCH 5
 #define IGRAPH_VERSION_PRERELEASE ""
 
-int igraph_version(const char **version_string,
+DECLDIR int igraph_version(const char **version_string,
                    int *major,
                    int *minor,
                    int *subminor);
diff --git a/igraph/include/igraph_visitor.h b/igraph/include/igraph_visitor.h
--- a/igraph/include/igraph_visitor.h
+++ b/igraph/include/igraph_visitor.h
@@ -62,7 +62,7 @@
  *    as a request to stop the BFS and return to the caller. If a BFS
  *    is terminated like this, then all elements of the result vectors
  *    that were not yet calculated at the point of the termination
- *    contain \c IGRAPH_NAN.
+ *    contain NaN.
  *
  * \sa \ref igraph_bfs()
  */
@@ -109,7 +109,7 @@
  *    as a request to stop the DFS and return to the caller. If a DFS
  *    is terminated like this, then all elements of the result vectors
  *    that were not yet calculated at the point of the termination
- *    contain \c IGRAPH_NAN.
+ *    contain NaN.
  *
  * \sa \ref igraph_dfs()
  */
diff --git a/igraph/include/infomap_FlowGraph.h b/igraph/include/infomap_FlowGraph.h
--- a/igraph/include/infomap_FlowGraph.h
+++ b/igraph/include/infomap_FlowGraph.h
@@ -62,7 +62,7 @@
     double alpha, beta;
 
     int Ndanglings;
-    vector<int> danglings; // id of dangling nodes
+    std::vector<int> danglings; // id of dangling nodes
 
     double exit;                  //
     double exitFlow;              //
diff --git a/igraph/include/infomap_Greedy.h b/igraph/include/infomap_Greedy.h
--- a/igraph/include/infomap_Greedy.h
+++ b/igraph/include/infomap_Greedy.h
@@ -69,16 +69,16 @@
     double alpha, beta;
     // local copy of fgraph alpha, beta (=alpha -  Nnode = graph->Nnode;1)
 
-    vector<int> node_index;  // module number of each node
+    std::vector<int> node_index;  // module number of each node
 
     int Nempty;
-    vector<int> mod_empty;
+    std::vector<int> mod_empty;
 
-    vector<double> mod_exit;  // version tmp de node
-    vector<double> mod_size;
-    vector<double> mod_danglingSize;
-    vector<double> mod_teleportWeight;
-    vector<int> mod_members;
+    std::vector<double> mod_exit;  // version tmp de node
+    std::vector<double> mod_size;
+    std::vector<double> mod_danglingSize;
+    std::vector<double> mod_teleportWeight;
+    std::vector<int> mod_members;
 };
 
 void delete_Greedy(Greedy *greedy);
diff --git a/igraph/include/infomap_Node.h b/igraph/include/infomap_Node.h
--- a/igraph/include/infomap_Node.h
+++ b/igraph/include/infomap_Node.h
@@ -30,18 +30,15 @@
 
 #include "igraph_interface.h"
 
-class Node;
-using namespace std;
-
 class Node {
 public:
 
     Node();
     Node(int modulenr, double tpweight);
 
-    vector<int> members;
-    vector< pair<int, double> > inLinks;
-    vector< pair<int, double> > outLinks;
+    std::vector<int> members;
+    std::vector< std::pair<int, double> > inLinks;
+    std::vector< std::pair<int, double> > outLinks;
     double selfLink;
 
     double teleportWeight;
diff --git a/igraph/include/plfit/error.h b/igraph/include/plfit/error.h
--- a/igraph/include/plfit/error.h
+++ b/igraph/include/plfit/error.h
@@ -4,14 +4,14 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/igraph/include/plfit/gss.h b/igraph/include/plfit/gss.h
--- a/igraph/include/plfit/gss.h
+++ b/igraph/include/plfit/gss.h
@@ -4,14 +4,14 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -55,7 +55,7 @@
  * The gss() function calls this function to obtain the values of the objective
  * function when needed. A client program must implement this function to evaluate
  * the value of the objective function, given the location.
- *  
+ *
  * @param  instance    The user data sent for the gss() function by the client.
  * @param  x           The current value of the variable.
  * @retval double      The value of the objective function for the current
diff --git a/igraph/include/plfit/hzeta.h b/igraph/include/plfit/hzeta.h
new file mode 100644
--- /dev/null
+++ b/igraph/include/plfit/hzeta.h
@@ -0,0 +1,96 @@
+/* This file was imported from a private scientific library
+ * based on GSL coined Home Scientific Libray (HSL) by its author
+ * Jerome Benoit; this very material is itself inspired from the
+ * material written by G. Jungan and distributed by GSL.
+ * Ultimately, some modifications were done in order to render the
+ * imported material independent from the rest of GSL.
+ */
+
+/* `hsl/hsl_sf_zeta.h' C header file
+// HSL - Home Scientific Library
+// Copyright (C) 2005-2018  Jerome Benoit
+//
+// HSL is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/* For futher details, see its source conterpart src/hzeta.c */
+
+/* Author:  Jerome G. Benoit < jgmbenoit _at_ rezozer _dot_ net > */
+
+#ifndef __HZETA_H__
+#define __HZETA_H__
+
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS /* empty */
+# define __END_DECLS /* empty */
+#endif
+
+__BEGIN_DECLS
+
+
+/* Hurwitz Zeta Function
+ * zeta(s,q) = Sum[ (k+q)^(-s), {k,0,Infinity} ]
+ *
+ * s > 1.0, q > 0.0
+ */
+double hsl_sf_hzeta(const double s, const double q);
+
+/* First Derivative of Hurwitz Zeta Function
+ * zeta'(s,q) = - Sum[ Ln(k+q)/(k+q)^(s), {k,0,Infinity} ]
+ *
+ * s > 1.0, q > 0.0
+ */
+double hsl_sf_hzeta_deriv(const double s, const double q);
+
+/* Second Derivative of Hurwitz Zeta Function
+ * zeta''(s,q) = + Sum[ Ln(k+q)^2/(k+q)^(s), {k,0,Infinity} ]
+ *
+ * s > 1.0, q > 0.0
+ */
+double hsl_sf_hzeta_deriv2(const double s, const double q);
+
+/* Logarithm of Hurwitz Zeta Function
+ * lnzeta(s,q) = ln(zeta(s,q))
+ *
+ * s > 1.0, q > 0.0 (and q >> 1)
+ */
+double hsl_sf_lnhzeta(const double s, const double q);
+
+/* Logarithmic Derivative of Hurwitz Zeta Function
+ * lnzeta'(s,q) = zeta'(s,q)/zeta(s,q)
+ *
+ * s > 1.0, q > 0.0 (and q >> 1)
+ */
+double hsl_sf_lnhzeta_deriv(const double s, const double q);
+
+/* Logarithm and Logarithmic Derivative of Hurwitz Zeta Function:
+ * nonredundant computation version:
+ * - lnzeta(s,q) and lnzeta'(s,q) are stored in *deriv0 and *deriv1, respectively;
+ * - the return value and the value stored in *deriv0 are the same;
+ * - deriv0 and deriv1 must be effective pointers, that is, not the NULL pointer.
+ *
+ * s > 1.0, q > 0.0 (and q >> 1)
+ */
+double hsl_sf_lnhzeta_deriv_tuple(const double s, const double q, double * deriv0, double * deriv1);
+
+
+__END_DECLS
+
+#endif // __HZETA_H__
diff --git a/igraph/include/plfit/kolmogorov.h b/igraph/include/plfit/kolmogorov.h
--- a/igraph/include/plfit/kolmogorov.h
+++ b/igraph/include/plfit/kolmogorov.h
@@ -1,17 +1,17 @@
 /* kolmogorov.h
- * 
+ *
  * Copyright (C) 2010-2011 Tamas Nepusz
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/igraph/include/plfit/mt.h b/igraph/include/plfit/mt.h
new file mode 100644
--- /dev/null
+++ b/igraph/include/plfit/mt.h
@@ -0,0 +1,103 @@
+/* mt.h
+ *
+ * Mersenne Twister random number generator, based on the implementation of
+ * Michael Brundage (which has been placed in the public domain).
+ *
+ * Author: Tamas Nepusz (original by Michael Brundage)
+ *
+ * See the following URL for the original implementation:
+ * http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation.html
+ *
+ * This file has been placed in the public domain.
+ */
+
+#ifndef __MT_H__
+#define __MT_H__
+
+/* VS 2010, i.e. _MSC_VER == 1600, already has stdint.h */
+#if defined(_MSC_VER) && _MSC_VER < 1600
+#  define uint32_t __int32
+#else
+#  include <stdint.h>
+#endif
+
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS /* empty */
+# define __END_DECLS /* empty */
+#endif
+
+__BEGIN_DECLS
+
+#define MT_LEN       624
+
+/**
+ * \def MT_RAND_MAX
+ *
+ * The maximum random number that \c mt_random() can generate.
+ */
+#define MT_RAND_MAX 0xFFFFFFFF
+
+/**
+ * Struct that stores the internal state of a Mersenne Twister random number
+ * generator.
+ */
+typedef struct {
+    int mt_index;
+    uint32_t mt_buffer[MT_LEN];
+} mt_rng_t;
+
+/**
+ * \brief Initializes a Mersenne Twister random number generator.
+ *
+ * The random number generator is seeded with random 32-bit numbers obtained
+ * from the \em built-in random number generator using consecutive calls to
+ * \c rand().
+ *
+ * \param  rng  the random number generator to initialize
+ */
+void mt_init(mt_rng_t* rng);
+
+/**
+ * \brief Initializes a Mersenne Twister random number generator, seeding it
+ *        from another one.
+ *
+ * The random number generator is seeded with random 32-bit numbers obtained
+ * from another, initialized Mersenne Twister random number generator.
+ *
+ * \param  rng     the random number generator to initialize
+ * \param  seeder  the random number generator that will seed the one being
+ *                 initialized. When null, the random number generator will
+ *                 be initialized from the built-in RNG as if \ref mt_init()
+ *                 was called.
+ */
+void mt_init_from_rng(mt_rng_t* rng, mt_rng_t* seeder);
+
+/**
+ * \brief Returns the next 32-bit random number from the given Mersenne Twister
+ * random number generator.
+ *
+ * \param  rng  the random number generator to use
+ * \return the next 32-bit random number from the generator
+ */
+uint32_t mt_random(mt_rng_t* rng);
+
+/**
+ * \brief Returns a uniformly distributed double from the interval [0;1)
+ * based on the next value of the given Mersenne Twister random number
+ * generator.
+ *
+ * \param  rng  the random number generator to use
+ * \return a uniformly distributed random number from the interval [0;1)
+ */
+double mt_uniform_01(mt_rng_t* rng);
+
+__END_DECLS
+
+#endif
+
+
diff --git a/igraph/include/plfit/platform.h b/igraph/include/plfit/platform.h
--- a/igraph/include/plfit/platform.h
+++ b/igraph/include/plfit/platform.h
@@ -4,14 +4,14 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -34,11 +34,22 @@
 
 __BEGIN_DECLS
 
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#include <math.h>
+
+#define snprintf igraph_i_snprintf
+#define isnan(x) ((x) != (x))
+#define isfinite(x) _finite(x)
+
+extern double _plfit_fmin(double a, double b);
+extern double _plfit_round(double x);
+
+#define fmin _plfit_fmin
+#define round _plfit_round
+#endif
+
 #ifdef _MSC_VER
-#define snprintf sprintf_s
 #define inline  __inline
-#define isnan(x) _isnan(x)
-#define isfinite(x) _finite(x)
 #endif
 
 #ifndef INFINITY
@@ -46,7 +57,7 @@
 #endif
 
 #ifndef NAN
-#  define NAN (INFINITY-INFINITY)
+#  define NAN ((double)0.0 / (double)DBL_MIN)
 #endif
 
 __END_DECLS
diff --git a/igraph/include/plfit/plfit.h b/igraph/include/plfit/plfit.h
--- a/igraph/include/plfit/plfit.h
+++ b/igraph/include/plfit/plfit.h
@@ -1,17 +1,18 @@
+/* vim:set ts=4 sw=4 sts=4 et: */
 /* plfit.h
- * 
+ *
  * Copyright (C) 2010-2011 Tamas Nepusz
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -21,6 +22,7 @@
 #define __PLFIT_H__
 
 #include <stdlib.h>
+#include "mt.h"
 
 #undef __BEGIN_DECLS
 #undef __END_DECLS
@@ -35,47 +37,61 @@
 __BEGIN_DECLS
 
 #define PLFIT_VERSION_MAJOR 0
-#define PLFIT_VERSION_MINOR 6
-#define PLFIT_VERSION_STRING "0.6"
+#define PLFIT_VERSION_MINOR 8
+#define PLFIT_VERSION_STRING "0.8"
 
 typedef unsigned short int plfit_bool_t;
 
 typedef enum {
-	PLFIT_GSS_OR_LINEAR,
-	PLFIT_LINEAR_ONLY,
-	PLFIT_DEFAULT_CONTINUOUS_METHOD = PLFIT_GSS_OR_LINEAR
+    PLFIT_LINEAR_ONLY,
+    PLFIT_STRATIFIED_SAMPLING,
+    PLFIT_GSS_OR_LINEAR,
+    PLFIT_DEFAULT_CONTINUOUS_METHOD = PLFIT_STRATIFIED_SAMPLING
 } plfit_continuous_method_t;
 
 typedef enum {
-	PLFIT_LBFGS,
-	PLFIT_LINEAR_SCAN,
-	PLFIT_PRETEND_CONTINUOUS,
-	PLFIT_DEFAULT_DISCRETE_METHOD = PLFIT_LBFGS
+    PLFIT_LBFGS,
+    PLFIT_LINEAR_SCAN,
+    PLFIT_PRETEND_CONTINUOUS,
+    PLFIT_DEFAULT_DISCRETE_METHOD = PLFIT_LBFGS
 } plfit_discrete_method_t;
 
+typedef enum {
+    PLFIT_P_VALUE_SKIP,
+    PLFIT_P_VALUE_APPROXIMATE,
+    PLFIT_P_VALUE_EXACT,
+    PLFIT_DEFAULT_P_VALUE_METHOD = PLFIT_P_VALUE_EXACT
+} plfit_p_value_method_t;
+
 typedef struct _plfit_result_t {
-	double alpha;     /* fitted power-law exponent */
-	double xmin;      /* cutoff where the power-law behaviour kicks in */
-	double L;         /* log-likelihood of the sample */
-	double D;         /* test statistic for the KS test */
-	double p;         /* p-value of the KS test */
+    double alpha;     /* fitted power-law exponent */
+    double xmin;      /* cutoff where the power-law behaviour kicks in */
+    double L;         /* log-likelihood of the sample */
+    double D;         /* test statistic for the KS test */
+    double p;         /* p-value of the KS test */
 } plfit_result_t;
 
 /********** structure that holds the options of plfit **********/
 
 typedef struct _plfit_continuous_options_t {
-	plfit_bool_t finite_size_correction;
-	plfit_continuous_method_t xmin_method;
+    plfit_bool_t finite_size_correction;
+    plfit_continuous_method_t xmin_method;
+    plfit_p_value_method_t p_value_method;
+    double p_value_precision;
+    mt_rng_t* rng;
 } plfit_continuous_options_t;
 
 typedef struct _plfit_discrete_options_t {
-	plfit_bool_t finite_size_correction;
-	plfit_discrete_method_t alpha_method;
-	struct {
-		double min;
-		double max;
-		double step;
-	} alpha;
+    plfit_bool_t finite_size_correction;
+    plfit_discrete_method_t alpha_method;
+    struct {
+        double min;
+        double max;
+        double step;
+    } alpha;
+    plfit_p_value_method_t p_value_method;
+    double p_value_precision;
+    mt_rng_t* rng;
 } plfit_discrete_options_t;
 
 int plfit_continuous_options_init(plfit_continuous_options_t* options);
@@ -87,23 +103,41 @@
 /********** continuous power law distribution fitting **********/
 
 int plfit_log_likelihood_continuous(double* xs, size_t n, double alpha,
-		double xmin, double* l);
+        double xmin, double* l);
 int plfit_estimate_alpha_continuous(double* xs, size_t n, double xmin,
         const plfit_continuous_options_t* options, plfit_result_t* result);
-int plfit_estimate_alpha_continuous_sorted(double* xs, size_t n, double xmin,
-        const plfit_continuous_options_t* options, plfit_result_t* result);
 int plfit_continuous(double* xs, size_t n,
-		const plfit_continuous_options_t* options, plfit_result_t* result);
+        const plfit_continuous_options_t* options, plfit_result_t* result);
 
-/********** discrete power law distribution fitting **********/
+/*********** discrete power law distribution fitting ***********/
 
 int plfit_estimate_alpha_discrete(double* xs, size_t n, double xmin,
         const plfit_discrete_options_t* options, plfit_result_t *result);
 int plfit_log_likelihood_discrete(double* xs, size_t n, double alpha, double xmin, double* l);
 int plfit_discrete(double* xs, size_t n, const plfit_discrete_options_t* options,
-		plfit_result_t* result);
+        plfit_result_t* result);
 
+/***** resampling routines to generate synthetic replicates ****/
+
+int plfit_resample_continuous(double* xs, size_t n, double alpha, double xmin,
+        size_t num_samples, mt_rng_t* rng, double* result);
+int plfit_resample_discrete(double* xs, size_t n, double alpha, double xmin,
+        size_t num_samples, mt_rng_t* rng, double* result);
+
+/******** calculating the p-value of a fitted model only *******/
+
+int plfit_calculate_p_value_continuous(double* xs, size_t n,
+        const plfit_continuous_options_t* options, plfit_bool_t xmin_fixed,
+        plfit_result_t *result);
+int plfit_calculate_p_value_discrete(double* xs, size_t n,
+        const plfit_discrete_options_t* options, plfit_bool_t xmin_fixed,
+        plfit_result_t *result);
+
+/************* calculating descriptive statistics **************/
+
+int plfit_moments(double* data, size_t n, double* mean, double* variance,
+        double* skewness, double* kurtosis);
+
 __END_DECLS
 
 #endif /* __PLFIT_H__ */
-
diff --git a/igraph/include/plfit/sampling.h b/igraph/include/plfit/sampling.h
new file mode 100644
--- /dev/null
+++ b/igraph/include/plfit/sampling.h
@@ -0,0 +1,177 @@
+/* sampling.h
+ *
+ * Copyright (C) 2012 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __SAMPLING_H__
+#define __SAMPLING_H__
+
+#include <stdlib.h>
+#include "mt.h"
+
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS /* empty */
+# define __END_DECLS /* empty */
+#endif
+
+__BEGIN_DECLS
+
+/**
+ * Draws a sample from a binomial distribution with the given count and
+ * probability values.
+ *
+ * This function is borrowed from R; see the corresponding license in
+ * \c rbinom.c. The return value is always an integer.
+ *
+ * The function is \em not thread-safe.
+ *
+ * \param  n    the number of trials
+ * \param  p    the success probability of each trial
+ * \param  rng  the Mersenne Twister random number generator to use
+ * \return the value drawn from the given binomial distribution.
+ */
+double plfit_rbinom(double n, double p, mt_rng_t* rng);
+
+/**
+ * Draws a sample from a Pareto distribution with the given minimum value and
+ * power-law exponent.
+ *
+ * \param  xmin    the minimum value of the distribution. Must be positive.
+ * \param  alpha   the exponent. Must be positive
+ * \param  rng     the Mersenne Twister random number generator to use
+ *
+ * \return the sample or NaN if one of the parameters is invalid
+ */
+extern double plfit_rpareto(double xmin, double alpha, mt_rng_t* rng);
+
+/**
+ * Draws a given number of samples from a Pareto distribution with the given
+ * minimum value and power-law exponent.
+ *
+ * \param  xmin    the minimum value of the distribution. Must be positive.
+ * \param  alpha   the exponent. Must be positive
+ * \param  n       the number of samples to draw
+ * \param  rng     the Mersenne Twister random number generator to use
+ * \param  result  the array where the result should be written. It must
+ *                 have enough space to store n items
+ *
+ * \return \c PLFIT_EINVAL if one of the parameters is invalid, zero otherwise
+ */
+int plfit_rpareto_array(double xmin, double alpha, size_t n, mt_rng_t* rng,
+        double* result);
+
+/**
+ * Draws a sample from a zeta distribution with the given minimum value and
+ * power-law exponent.
+ *
+ * \param  xmin    the minimum value of the distribution. Must be positive.
+ * \param  alpha   the exponent. Must be positive
+ * \param  rng     the Mersenne Twister random number generator to use
+ *
+ * \return the sample or NaN if one of the parameters is invalid
+ */
+extern double plfit_rzeta(long int xmin, double alpha, mt_rng_t* rng);
+
+/**
+ * Draws a given number of samples from a zeta distribution with the given
+ * minimum value and power-law exponent.
+ *
+ * \param  xmin    the minimum value of the distribution. Must be positive.
+ * \param  alpha   the exponent. Must be positive
+ * \param  n       the number of samples to draw
+ * \param  rng     the Mersenne Twister random number generator to use
+ * \param  result  the array where the result should be written. It must
+ *                 have enough space to store n items
+ *
+ * \return \c PLFIT_EINVAL if one of the parameters is invalid, zero otherwise
+ */
+int plfit_rzeta_array(long int xmin, double alpha, size_t n, mt_rng_t* rng,
+        double* result);
+
+/**
+ * Draws a sample from a uniform distribution with the given lower and
+ * upper bounds.
+ *
+ * The lower bound is inclusive, the uppoer bound is not.
+ *
+ * \param  lo   the lower bound
+ * \param  hi   the upper bound
+ * \param  rng  the Mersenne Twister random number generator to use
+ * \return the value drawn from the given uniform distribution.
+ */
+extern double plfit_runif(double lo, double hi, mt_rng_t* rng);
+
+/**
+ * Draws a sample from a uniform distribution over the [0; 1) interval.
+ *
+ * The interval is closed from the left and open from the right.
+ *
+ * \param  rng  the Mersenne Twister random number generator to use
+ * \return the value drawn from the given uniform distribution.
+ */
+extern double plfit_runif_01(mt_rng_t* rng);
+
+/**
+ * Random sampler using Walker's alias method.
+ */
+typedef struct {
+    long int num_bins;            /**< Number of bins */
+    long int* indexes;            /**< Index of the "other" element in each bin */
+    double* probs;                /**< Probability of drawing the "own" element from a bin */
+} plfit_walker_alias_sampler_t;
+
+/**
+ * \brief Initializes the sampler with item probabilities.
+ *
+ * \param  sampler  the sampler to initialize
+ * \param  ps   pointer to an array containing a value proportional to the
+ *              sampling probability of each item in the set being sampled.
+ * \param  n    the number of items in the array
+ * \return error code
+ */
+int plfit_walker_alias_sampler_init(plfit_walker_alias_sampler_t* sampler,
+        double* ps, size_t n);
+
+/**
+ * \brief Destroys an initialized sampler and frees the allocated memory.
+ *
+ * \param  sampler  the sampler to destroy
+ */
+void plfit_walker_alias_sampler_destroy(plfit_walker_alias_sampler_t* sampler);
+
+/**
+ * \brief Draws a given number of samples from the sampler and writes them
+ *        to a given array.
+ *
+ * \param  sampler  the sampler to use
+ * \param  xs       pointer to an array where the sampled items should be
+ *                  written
+ * \param  n        the number of samples to draw
+ * \param  rng      the Mersenne Twister random number generator to use
+ * \return error code
+ */
+int plfit_walker_alias_sampler_sample(const plfit_walker_alias_sampler_t* sampler,
+        long int* xs, size_t n, mt_rng_t* rng);
+
+__END_DECLS
+
+#endif
diff --git a/igraph/include/plfit/zeta.h b/igraph/include/plfit/zeta.h
deleted file mode 100644
--- a/igraph/include/plfit/zeta.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* specfunc/gsl_sf_zeta.h
- * 
- * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
- * your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* Author:  G. Jungman */
-
-/* This file was taken from the GNU Scientific Library. Some modifications
- * were done in order to make it independent from the rest of GSL
- */
-
-#ifndef __ZETA_H__
-#define __ZETA_H__
-
-#undef __BEGIN_DECLS
-#undef __END_DECLS
-#ifdef __cplusplus
-# define __BEGIN_DECLS extern "C" {
-# define __END_DECLS }
-#else
-# define __BEGIN_DECLS /* empty */
-# define __END_DECLS /* empty */
-#endif
-
-__BEGIN_DECLS
-
-
-/* Hurwitz Zeta Function
- * zeta(s,q) = Sum[ (k+q)^(-s), {k,0,Infinity} ]
- *
- * s > 1.0, q > 0.0
- */
-double gsl_sf_hzeta(const double s, const double q);
-
-
-__END_DECLS
-
-#endif /* __ZETA_H__ */
-
diff --git a/igraph/include/pottsmodel_2.h b/igraph/include/pottsmodel_2.h
--- a/igraph/include/pottsmodel_2.h
+++ b/igraph/include/pottsmodel_2.h
diff --git a/igraph/include/prpack/prpack_base_graph.h b/igraph/include/prpack/prpack_base_graph.h
--- a/igraph/include/prpack/prpack_base_graph.h
+++ b/igraph/include/prpack/prpack_base_graph.h
@@ -37,6 +37,6 @@
             void normalize_weights();
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_csc.h b/igraph/include/prpack/prpack_csc.h
--- a/igraph/include/prpack/prpack_csc.h
+++ b/igraph/include/prpack/prpack_csc.h
@@ -25,6 +25,6 @@
             int64_t* heads;
             int64_t* tails;
     };
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_csr.h b/igraph/include/prpack/prpack_csr.h
--- a/igraph/include/prpack/prpack_csr.h
+++ b/igraph/include/prpack/prpack_csr.h
@@ -11,6 +11,6 @@
             int* tails;
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_edge_list.h b/igraph/include/prpack/prpack_edge_list.h
--- a/igraph/include/prpack/prpack_edge_list.h
+++ b/igraph/include/prpack/prpack_edge_list.h
@@ -11,6 +11,6 @@
             int* tails;
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_igraph_graph.h b/igraph/include/prpack/prpack_igraph_graph.h
--- a/igraph/include/prpack/prpack_igraph_graph.h
+++ b/igraph/include/prpack/prpack_igraph_graph.h
@@ -17,7 +17,7 @@
 					igraph_bool_t directed = true);
     };
 
-};
+}
 
 // PRPACK_IGRAPH_SUPPORT 
 #endif 
diff --git a/igraph/include/prpack/prpack_preprocessed_ge_graph.h b/igraph/include/prpack/prpack_preprocessed_ge_graph.h
--- a/igraph/include/prpack/prpack_preprocessed_ge_graph.h
+++ b/igraph/include/prpack/prpack_preprocessed_ge_graph.h
@@ -21,6 +21,6 @@
             ~prpack_preprocessed_ge_graph();
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_preprocessed_graph.h b/igraph/include/prpack/prpack_preprocessed_graph.h
--- a/igraph/include/prpack/prpack_preprocessed_graph.h
+++ b/igraph/include/prpack/prpack_preprocessed_graph.h
@@ -12,6 +12,6 @@
             double* d;
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_preprocessed_gs_graph.h b/igraph/include/prpack/prpack_preprocessed_gs_graph.h
--- a/igraph/include/prpack/prpack_preprocessed_gs_graph.h
+++ b/igraph/include/prpack/prpack_preprocessed_gs_graph.h
@@ -25,6 +25,6 @@
             ~prpack_preprocessed_gs_graph();
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_preprocessed_scc_graph.h b/igraph/include/prpack/prpack_preprocessed_scc_graph.h
--- a/igraph/include/prpack/prpack_preprocessed_scc_graph.h
+++ b/igraph/include/prpack/prpack_preprocessed_scc_graph.h
@@ -34,6 +34,6 @@
             ~prpack_preprocessed_scc_graph();
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_preprocessed_schur_graph.h b/igraph/include/prpack/prpack_preprocessed_schur_graph.h
--- a/igraph/include/prpack/prpack_preprocessed_schur_graph.h
+++ b/igraph/include/prpack/prpack_preprocessed_schur_graph.h
@@ -28,6 +28,6 @@
             ~prpack_preprocessed_schur_graph();
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_result.h b/igraph/include/prpack/prpack_result.h
--- a/igraph/include/prpack/prpack_result.h
+++ b/igraph/include/prpack/prpack_result.h
@@ -1,6 +1,8 @@
 #ifndef PRPACK_RESULT
 #define PRPACK_RESULT
 
+#include <string>
+
 namespace prpack {
 
     // Result class.
@@ -14,7 +16,7 @@
             double preprocess_time;
             double compute_time;
             long num_es_touched;
-            const char* method;
+            std::string method;
             int converged;
             // constructor
             prpack_result();
@@ -22,6 +24,6 @@
             ~prpack_result();
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_solver.h b/igraph/include/prpack/prpack_solver.h
--- a/igraph/include/prpack/prpack_solver.h
+++ b/igraph/include/prpack/prpack_solver.h
@@ -173,6 +173,6 @@
                     const char* method);
     };
 
-};
+}
 
 #endif
diff --git a/igraph/include/prpack/prpack_utils.h b/igraph/include/prpack/prpack_utils.h
--- a/igraph/include/prpack/prpack_utils.h
+++ b/igraph/include/prpack/prpack_utils.h
@@ -28,7 +28,7 @@
             static double* permute(const int length, const double* a, const int* coding);
     };
 
-};
+}
 
 #endif
 
diff --git a/igraph/include/scg_headers.h b/igraph/include/scg_headers.h
--- a/igraph/include/scg_headers.h
+++ b/igraph/include/scg_headers.h
@@ -55,11 +55,11 @@
 #ifndef SCG_HEADERS_H
 #define SCG_HEADERS_H
 
-#include <stdio.h>
-#include <stdlib.h>
-
 #include "igraph_types.h"
 #include "igraph_vector.h"
+
+#include <stdio.h>
+#include <stdlib.h>
 
 typedef struct ind_val {
     int ind;
diff --git a/igraph/include/vector.pmt b/igraph/include/vector.pmt
--- a/igraph/include/vector.pmt
+++ b/igraph/include/vector.pmt
@@ -754,17 +754,27 @@
 
 /**
  * \ingroup vector
+ * \function igraph_vector_reverse_sort_cmp
+ * \brief Internal comparison function of vector elements, used by
+ * \ref igraph_vector_reverse_sort().
+ */
+
+int FUNCTION(igraph_vector, reverse_sort_cmp)(const void *a, const void *b) {
+    const BASE *da = (const BASE *) a;
+    const BASE *db = (const BASE *) b;
+
+    return (*da < *db) - (*da > *db);
+}
+
+/**
+ * \ingroup vector
  * \function igraph_vector_sort
  * \brief Sorts the elements of the vector into ascending order.
  *
- * </para><para>
- * This function uses the built-in sort function of the C library.
  * \param v Pointer to an initialized vector object.
  *
- * Time complexity: should be
- * O(nlogn) for
- * n
- * elements.
+ * Time complexity:
+ * O(n log n) for n elements.
  */
 
 void FUNCTION(igraph_vector, sort)(TYPE(igraph_vector) *v) {
@@ -775,6 +785,24 @@
 }
 
 /**
+ * \ingroup vector
+ * \function igraph_vector_reverse_sort
+ * \brief Sorts the elements of the vector into descending order.
+ *
+ * \param v Pointer to an initialized vector object.
+ *
+ * Time complexity:
+ * O(n log n) for n elements.
+ */
+
+void FUNCTION(igraph_vector, reverse_sort)(TYPE(igraph_vector) *v) {
+    assert(v != NULL);
+    assert(v->stor_begin != NULL);
+    igraph_qsort(v->stor_begin, (size_t) FUNCTION(igraph_vector, size)(v),
+                 sizeof(BASE), FUNCTION(igraph_vector, reverse_sort_cmp));
+}
+
+/**
  * Ascending comparison function passed to qsort from  igraph_vector_qsort_ind
  */
 int FUNCTION(igraph_vector, i_qsort_ind_cmp_asc)(const void *p1, const void *p2) {
@@ -1710,6 +1738,51 @@
             0, FUNCTION(igraph_vector, size)(v));
 }
 
+/**
+ * \ingroup vector
+ * \function igraph_vector_binsearch_slice
+ * \brief Finds an element by binary searching a sorted slice of a vector.
+ *
+ * </para><para>
+
+ * It is assumed that the indicated slice of the vector, from \p start to \p end,
+ * is sorted. If the specified element (\p what) is not in the slice of the
+ * vector, then the position of where it should be inserted (to keep the vector
+ * sorted) is returned.
+ * \param v The \type igraph_vector_t object.
+ * \param what The element to search for.
+ * \param pos Pointer to a \type long int. This is set to the position of an
+ *        instance of \p what in the slice of the vector if it is present. If \p
+ *        v does not contain \p what then \p pos is set to the position to which
+ *        it should be inserted (to keep the the vector sorted).
+ * \param start The start position of the slice to search (inclusive).
+ * \param end The end position of the slice to search (exclusive).
+ * \return Positive integer (true) if \p what is found in the vector,
+ *         zero (false) otherwise.
+ *
+ * Time complexity: O(log(n)),
+ * n is the number of elements in the slice of \p v, i.e. \p end - \p start.
+ */
+
+igraph_bool_t FUNCTION(igraph_vector, binsearch_slice)(const TYPE(igraph_vector) *v,
+        BASE what, long int *pos,
+        long int start, long int end) {
+    long int left  = start;
+    long int right = end - 1;
+
+    if (left < 0)
+        IGRAPH_ERROR("Invalid start position.", IGRAPH_EINVAL);
+
+    if (right >= FUNCTION(igraph_vector, size)(v))
+        IGRAPH_ERROR("Invalid end position.", IGRAPH_EINVAL);
+
+    if (left > right)
+        IGRAPH_ERROR("Invalid slice, start position must be smaller than end position.",
+                     IGRAPH_EINVAL);
+
+    return FUNCTION(igraph_i_vector, binsearch_slice)(v, what, pos, start, end);
+}
+
 igraph_bool_t FUNCTION(igraph_i_vector, binsearch_slice)(const TYPE(igraph_vector) *v,
         BASE what, long int *pos,
         long int start, long int end) {
@@ -1930,7 +2003,7 @@
  * \function igraph_vector_append
  * \brief Append a vector to another one.
  *
- * The target vector will be resized (except \p from is empty).
+ * The target vector will be resized (except when \p from is empty).
  * \param to The vector to append to.
  * \param from The vector to append, it is kept unchanged.
  * \return Error code.
@@ -2008,8 +2081,8 @@
  * \brief Update a vector from another one.
  *
  * After this operation the contents of \p to will be exactly the same
- * \p from. \p to will be resized if it was originally shorter or
- * longer than \p from.
+ * as that of \p from. The vector \p to will be resized if it was originally
+ * shorter or longer than \p from.
  * \param to The vector to update.
  * \param from The vector to update from.
  * \return Error code.
@@ -2063,8 +2136,8 @@
  * Note that currently no range checking is performed.
  * \param v The input vector.
  * \param i Index of the first element.
- * \param j index of the second element. (Might be the same as the
- * first.)
+ * \param j Index of the second element (may be the same as the
+ * first one).
  * \return Error code, currently always \c IGRAPH_SUCCESS.
  *
  * Time complexity: O(1).
@@ -2110,7 +2183,7 @@
  * \brief Shuffles a vector in-place using the Fisher-Yates method
  *
  * </para><para>
- * The Fisher-Yates shuffle ensures that every implementation is
+ * The Fisher-Yates shuffle ensures that every permutation is
  * equally probable when using a proper randomness source. Of course
  * this does not apply to pseudo-random generators as the cycle of
  * these generators is less than the number of possible permutations
diff --git a/igraph/include/walktrap_communities.h b/igraph/include/walktrap_communities.h
--- a/igraph/include/walktrap_communities.h
+++ b/igraph/include/walktrap_communities.h
@@ -54,12 +54,11 @@
 // see readme.txt for more details
 
 
-#ifndef COMMUNITIES_H
-#define COMMUNITIES_H
+#ifndef WALKTRAP_COMMUNITIES_H
+#define WALKTRAP_COMMUNITIES_H
 
 #include "walktrap_graph.h"
 #include "walktrap_heap.h"
-
 #include "igraph_community.h"
 #include "config.h"
 
@@ -173,4 +172,4 @@
 }
 }       /* end of namespaces */
 
-#endif
+#endif // WALKTRAP_COMMUNITIES_H
diff --git a/igraph/include/walktrap_graph.h b/igraph/include/walktrap_graph.h
--- a/igraph/include/walktrap_graph.h
+++ b/igraph/include/walktrap_graph.h
@@ -55,9 +55,8 @@
 /* FSF address above was fixed by Tamas Nepusz */
 
 
-#ifndef GRAPH_H
-#define GRAPH_H
-#include <iostream>
+#ifndef WALKTRAP_GRAPH_H
+#define WALKTRAP_GRAPH_H
 
 #include "igraph_community.h"
 
@@ -65,8 +64,6 @@
 
 namespace walktrap {
 
-using namespace std;
-
 class Edge {            // code an edge of a given vertex
 public:
     int neighbor;         // the number of the neighbor vertex
@@ -104,5 +101,5 @@
 }
 }        /* end of namespaces */
 
-#endif
+#endif // WALKTRAP_GRAPH_H
 
diff --git a/igraph/include/walktrap_heap.h b/igraph/include/walktrap_heap.h
--- a/igraph/include/walktrap_heap.h
+++ b/igraph/include/walktrap_heap.h
@@ -53,8 +53,8 @@
 //-----------------------------------------------------------------------------
 // see readme.txt for more details
 
-#ifndef HEAP_H
-#define HEAP_H
+#ifndef WALKTRAP_HEAP_H
+#define WALKTRAP_HEAP_H
 
 namespace igraph {
 
@@ -130,5 +130,5 @@
 }
 }        /* end of namespaces */
 
-#endif
+#endif // WALKTRAP_HEAP_H
 
diff --git a/igraph/src/DensityGrid.cpp b/igraph/src/DensityGrid.cpp
--- a/igraph/src/DensityGrid.cpp
+++ b/igraph/src/DensityGrid.cpp
@@ -33,17 +33,14 @@
 // This file contains the member definitions of the DensityGrid.h class
 // This code is modified from the original code by B.N. Wylie
 
-#include <string>
+#include "drl_Node.h"
+#include "DensityGrid.h"
+#include "igraph_error.h"
+
 #include <deque>
-#include <iostream>
 #include <cmath>
-#include <cstdlib>
 
 using namespace std;
-
-#include "drl_Node.h"
-#include "DensityGrid.h"
-#include "igraph_error.h"
 
 #define GET_BIN(y, x) (Bins[y*GRID_SIZE+x])
 
diff --git a/igraph/src/DensityGrid_3d.cpp b/igraph/src/DensityGrid_3d.cpp
--- a/igraph/src/DensityGrid_3d.cpp
+++ b/igraph/src/DensityGrid_3d.cpp
@@ -33,17 +33,14 @@
 // This file contains the member definitions of the DensityGrid.h class
 // This code is modified from the original code by B.N. Wylie
 
-#include <string>
+#include "drl_Node_3d.h"
+#include "DensityGrid_3d.h"
+#include "igraph_error.h"
+
 #include <deque>
-#include <iostream>
 #include <cmath>
-#include <cstdlib>
 
 using namespace std;
-
-#include "drl_Node_3d.h"
-#include "DensityGrid_3d.h"
-#include "igraph_error.h"
 
 #define GET_BIN(z, y, x) (Bins[(z*GRID_SIZE+y)*GRID_SIZE+x])
 
diff --git a/igraph/src/NetDataTypes.cpp b/igraph/src/NetDataTypes.cpp
--- a/igraph/src/NetDataTypes.cpp
+++ b/igraph/src/NetDataTypes.cpp
@@ -43,10 +43,9 @@
 #ifdef HAVE_CONFIG_H
     #include <config.h>
 #endif
-#include <cstdlib>
-#include <cstdio>
-#include <cstring>
+
 #include "NetDataTypes.h"
+#include <cstring>
 
 //#################################################################################
 //###############################################################################
diff --git a/igraph/src/NetRoutines.cpp b/igraph/src/NetRoutines.cpp
--- a/igraph/src/NetRoutines.cpp
+++ b/igraph/src/NetRoutines.cpp
@@ -40,15 +40,15 @@
  *   (at your option) any later version.                                   *
  *                                                                         *
  ***************************************************************************/
-#include <cstdlib>
-#include <cstdio>
-#include <cstring>
+
 #include "NetRoutines.h"
 #include "NetDataTypes.h"
 
 #include "igraph_types.h"
 #include "igraph_interface.h"
 #include "igraph_conversion.h"
+
+#include <cstring>
 
 int igraph_i_read_network(const igraph_t *graph,
                           const igraph_vector_t *weights,
diff --git a/igraph/src/adjlist.c b/igraph/src/adjlist.c
--- a/igraph/src/adjlist.c
+++ b/igraph/src/adjlist.c
@@ -37,7 +37,7 @@
  * neighbor vertices or incident edges of a given vertex. Typically,
  * this representation is good if we need to iterate over the neighbors
  * of all vertices many times. E.g. when finding the shortest paths
- * between every pairs of vertices or calculating closeness centrality
+ * between all pairs of vertices or calculating closeness centrality
  * for all the vertices.</para>
  *
  * <para>The <type>igraph_adjlist_t</type> stores the adjacency lists
@@ -61,7 +61,7 @@
  * the neighbors of v are queried and stored in a vector of the
  * adjacency list, so they don't need to be queried again. Lazy
  * adjacency lists are handy if you have an at least linear operation
- * (because initialization is generally linear in terms of number of
+ * (because initialization is generally linear in terms of the number of
  * vertices), but you don't know how many vertices you will visit
  * during the computation.
  * </para>
@@ -73,9 +73,9 @@
 
 /**
  * \function igraph_adjlist_init
- * Initialize an adjacency list of vertices from a given graph
+ * \brief Constructs an adjacency list of vertices from a given graph.
  *
- * Create a list of vectors containing the neighbors of all vertices
+ * Creates a list of vectors containing the neighbors of all vertices
  * in a graph. The adjacency list is independent of the graph after
  * creation, e.g. the graph can be destroyed and modified, the
  * adjacency list contains the state of the graph at the time of its
@@ -133,7 +133,7 @@
 
 /**
  * \function igraph_adjlist_init_empty
- * Initialize an empty adjacency list
+ * \brief Initializes an empty adjacency list.
  *
  * Creates a list of vectors, one for each vertex. This is useful when you
  * are \em constructing a graph using an adjacency list representation as
@@ -165,7 +165,7 @@
 
 /**
  * \function igraph_adjlist_init_complementer
- * Adjacency lists for the complementer graph
+ * \brief Adjacency lists for the complementer graph.
  *
  * This function creates adjacency lists for the complementer
  * of the input graph. In the complementer graph all edges are present
@@ -248,7 +248,7 @@
 
 /**
  * \function igraph_adjlist_destroy
- * Deallocate memory
+ * \brief Deallocates an adjacency list.
  *
  * Free all memory allocated for an adjacency list.
  * \param al The adjacency list to destroy.
@@ -283,7 +283,7 @@
 
 /**
  * \function igraph_adjlist_size
- * Number of vertices in an adjacency list.
+ * \brief Number of vertices in an adjacency list.
  *
  * \param al The adjacency list.
  * \return The number of elements.
@@ -301,7 +301,7 @@
 
 /**
  * \function igraph_adjlist_sort
- * Sort each vector in an adjacency list.
+ * \brief Sorts each vector in an adjacency list.
  *
  * Sorts every vector of the adjacency list.
  * \param al The adjacency list.
@@ -319,9 +319,10 @@
 
 /**
  * \function igraph_adjlist_simplify
- * Simplify
+ * \brief Simplifies an adjacency list.
  *
- * Simplify an adjacency list, ie. remove loop and multiple edges.
+ * Simplifies an adjacency list, i.e. removes loop and multiple edges.
+ *
  * \param al The adjacency list.
  * \return Error code.
  *
@@ -359,21 +360,27 @@
 
 int igraph_adjlist_remove_duplicate(const igraph_t *graph,
                                     igraph_adjlist_t *al) {
-    long int i;
-    long int n = al->length;
+    long int i, j, l, n, p;
+    igraph_vector_int_t *v;
+
     IGRAPH_UNUSED(graph);
+
+    n = al->length;
     for (i = 0; i < n; i++) {
-        igraph_vector_int_t *v = &al->adjs[i];
-        long int j, p = 1, l = igraph_vector_int_size(v);
-        for (j = 1; j < l; j++) {
-            long int e = (long int) VECTOR(*v)[j];
-            /* Non-loop edges, and one end of loop edges are fine. */
-            /* We use here, that the vector is sorted and we also keep it sorted */
-            if (e != i || VECTOR(*v)[j - 1] != e) {
-                VECTOR(*v)[p++] = e;
+        v = &al->adjs[i];
+        l = igraph_vector_int_size(v);
+        if (l > 0) {
+            p = 1;
+            for (j = 1; j < l; j++) {
+                long int e = (long int) VECTOR(*v)[j];
+                /* Non-loop edges, and one end of loop edges are fine. */
+                /* We assume that the vector is sorted and we also keep it sorted */
+                if (e != i || VECTOR(*v)[j - 1] != e) {
+                    VECTOR(*v)[p++] = e;
+                }
             }
+            igraph_vector_int_resize(v, p);
         }
-        igraph_vector_int_resize(v, p);
     }
 
     return 0;
@@ -466,7 +473,7 @@
 
 /**
  * \function igraph_adjedgelist_init
- * Initialize an incidence list of edges
+ * \brief Initializes an incidence list of edges.
  *
  * This function was superseded by \ref igraph_inclist_init() in igraph 0.6.
  * Please use \ref igraph_inclist_init() instead of this function.
@@ -484,7 +491,7 @@
 
 /**
  * \function igraph_adjedgelist_destroy
- * Frees all memory allocated for an incidence list.
+ * \brief Frees all memory allocated for an incidence list.
  *
  * This function was superseded by \ref igraph_inclist_destroy() in igraph 0.6.
  * Please use \ref igraph_inclist_destroy() instead of this function.
@@ -500,21 +507,25 @@
 
 int igraph_inclist_remove_duplicate(const igraph_t *graph,
                                     igraph_inclist_t *al) {
-    long int i;
-    long int n = al->length;
+    long int i, j, l, n, p;
+    igraph_vector_int_t* v;
+
+    n = al->length;
     for (i = 0; i < n; i++) {
-        igraph_vector_int_t *v = &al->incs[i];
-        long int j, p = 1, l = igraph_vector_int_size(v);
-        for (j = 1; j < l; j++) {
-            long int e = (long int) VECTOR(*v)[j];
-            /* Non-loop edges and one end of loop edges are fine. */
-            /* We use here, that the vector is sorted and we also keep it sorted */
-            if (IGRAPH_FROM(graph, e) != IGRAPH_TO(graph, e) ||
-                VECTOR(*v)[j - 1] != e) {
-                VECTOR(*v)[p++] = e;
+        v = &al->incs[i];
+        l = igraph_vector_int_size(v);
+        if (l > 0) {
+            p = 1;
+            for (j = 1; j < l; j++) {
+                long int e = (long int) VECTOR(*v)[j];
+                /* Non-loop edges and one end of loop edges are fine. */
+                /* We assume that the vector is sorted and we also keep it sorted */
+                if (VECTOR(*v)[j - 1] != e) {
+                    VECTOR(*v)[p++] = e;
+                }
             }
+            igraph_vector_int_resize(v, p);
         }
-        igraph_vector_int_resize(v, p);
     }
 
     return 0;
@@ -544,13 +555,21 @@
 
 /**
  * \function igraph_inclist_init
- * Initialize an incidence list of edges
+ * \brief Initializes an incidence list.
  *
- * Create a list of vectors containing the incident edges for all
+ * Creates a list of vectors containing the incident edges for all
  * vertices. The incidence list is independent of the graph after
  * creation, subsequent changes of the graph object do not update the
  * incidence list, and changes to the incidence list do not update the
  * graph.
+ *
+ * </para><para>
+ * When \p mode is \c IGRAPH_IN or \c IGRAPH_OUT, each edge ID will appear
+ * in the incidence list \em once. When \p mode is \c IGRAPH_ALL, each edge ID
+ * will appear in the incidence list \em twice, once for the source vertex
+ * and once for the target edge. It also means that the edge IDs of loop edges
+ * will appear \em twice for the \em same vertex.
+ *
  * \param graph The input graph.
  * \param il Pointer to an uninitialized incidence list.
  * \param mode Constant specifying whether incoming edges
@@ -605,7 +624,7 @@
 
 /**
  * \function igraph_inclist_init_empty
- * \brief Initialize an incidence list corresponding to an empty graph.
+ * \brief Initializes an incidence list corresponding to an empty graph.
  *
  * This function essentially creates a list of empty vectors that may
  * be treated as an incidence list for a graph with a given number of
@@ -638,7 +657,7 @@
 
 /**
  * \function igraph_inclist_destroy
- * Frees all memory allocated for an incidence list.
+ * \brief Frees all memory allocated for an incidence list.
  *
  * \param eal The incidence list to destroy.
  *
@@ -657,7 +676,7 @@
 
 /**
  * \function igraph_inclist_clear
- * Removes all edges from an incidence list.
+ * \brief Removes all edges from an incidence list.
  *
  * \param il The incidence list.
  * Time complexity: depends on memory management, typically O(n), where n is
@@ -672,7 +691,7 @@
 
 /**
  * \function igraph_lazy_adjlist_init
- * Constructor
+ * \brief Initialized a lazy adjacency list.
  *
  * Create a lazy adjacency list for vertices. This function only
  * allocates some memory for storing the vectors of an adjacency list,
@@ -720,7 +739,7 @@
 
 /**
  * \function igraph_lazy_adjlist_destroy
- * Deallocate memory
+ * \brief Deallocate a lazt adjacency list.
  *
  * Free all allocated memory for a lazy adjacency list.
  * \param al The adjacency list to deallocate.
@@ -735,7 +754,7 @@
 
 /**
  * \function igraph_lazy_adjlist_clear
- * Removes all edges from a lazy adjacency list.
+ * \brief Removes all edges from a lazy adjacency list.
  *
  * \param al The lazy adjacency list.
  * Time complexity: depends on memory management, typically O(n), where n is
@@ -789,7 +808,7 @@
 
 /**
  * \function igraph_lazy_adjedgelist_init
- * Initializes a lazy incidence list of edges
+ * \brief Initializes a lazy incidence list of edges.
  *
  * This function was superseded by \ref igraph_lazy_inclist_init() in igraph 0.6.
  * Please use \ref igraph_lazy_inclist_init() instead of this function.
@@ -807,7 +826,7 @@
 
 /**
  * \function igraph_lazy_adjedgelist_destroy
- * Frees all memory allocated for an incidence list.
+ * \brief Frees all memory allocated for an incidence list.
  *
  * This function was superseded by \ref igraph_lazy_inclist_destroy() in igraph 0.6.
  * Please use \ref igraph_lazy_inclist_destroy() instead of this function.
@@ -830,17 +849,25 @@
 
 /**
  * \function igraph_lazy_inclist_init
- * Initializes a lazy incidence list of edges
+ * \brief Initializes a lazy incidence list of edges.
  *
  * Create a lazy incidence list for edges. This function only
  * allocates some memory for storing the vectors of an incidence list,
  * but the incident edges are not queried, only when \ref
  * igraph_lazy_inclist_get() is called.
+ *
+ * </para><para>
+ * When \p mode is \c IGRAPH_IN or \c IGRAPH_OUT, each edge ID will appear
+ * in the incidence list \em once. When \p mode is \c IGRAPH_ALL, each edge ID
+ * will appear in the incidence list \em twice, once for the source vertex
+ * and once for the target edge. It also means that the edge IDs of loop edges
+ * will appear \em twice for the \em same vertex.
+ *
  * \param graph The input graph.
  * \param al Pointer to an uninitialized incidence list.
  * \param mode Constant, it gives whether incoming edges
  *   (<code>IGRAPH_IN</code>), outgoing edges
- *   (<code>IGRPAH_OUT</code>) or both types of edges
+ *   (<code>IGRAPH_OUT</code>) or both types of edges
  *   (<code>IGRAPH_ALL</code>) are considered. It is ignored for
  *   undirected graphs.
  * \return Error code.
@@ -876,7 +903,7 @@
 
 /**
  * \function igraph_lazy_inclist_destroy
- * Deallocates memory
+ * \brief Deallocates a lazy incidence list.
  *
  * Frees all allocated memory for a lazy incidence list.
  * \param al The incidence list to deallocate.
@@ -891,9 +918,10 @@
 
 /**
  * \function igraph_lazy_inclist_clear
- * Removes all edges from a lazy incidence list.
+ * \brief Removes all edges from a lazy incidence list.
  *
  * \param il The lazy incidence list.
+ *
  * Time complexity: depends on memory management, typically O(n), where n is
  * the total number of elements in the incidence list.
  */
diff --git a/igraph/src/arpack.c b/igraph/src/arpack.c
--- a/igraph/src/arpack.c
+++ b/igraph/src/arpack.c
@@ -32,7 +32,7 @@
 
 /* The ARPACK example file dssimp.f is used as a template */
 
-int igraph_i_arpack_err_dsaupd(int error) {
+static int igraph_i_arpack_err_dsaupd(int error) {
     switch (error) {
     case  1:      return IGRAPH_ARPACK_MAXIT;
     case  3:      return IGRAPH_ARPACK_NOSHIFT;
@@ -54,7 +54,7 @@
     }
 }
 
-int igraph_i_arpack_err_dseupd(int error) {
+static int igraph_i_arpack_err_dseupd(int error) {
     switch (error) {
     case -1:      return IGRAPH_ARPACK_NPOS;
     case -2:      return IGRAPH_ARPACK_NEVNPOS;
@@ -76,7 +76,7 @@
 
 }
 
-int igraph_i_arpack_err_dnaupd(int error) {
+static int igraph_i_arpack_err_dnaupd(int error) {
     switch (error) {
     case  1:      return IGRAPH_ARPACK_MAXIT;
     case  3:      return IGRAPH_ARPACK_NOSHIFT;
@@ -97,7 +97,7 @@
     }
 }
 
-int igraph_i_arpack_err_dneupd(int error) {
+static int igraph_i_arpack_err_dneupd(int error) {
     switch (error) {
     case  1:      return IGRAPH_ARPACK_REORDER;
     case -1:      return IGRAPH_ARPACK_NPOS;
@@ -258,9 +258,9 @@
  * "Solver" for 1x1 eigenvalue problems since ARPACK sometimes blows up with
  * these.
  */
-int igraph_i_arpack_rssolve_1x1(igraph_arpack_function_t *fun, void *extra,
-                                igraph_arpack_options_t* options,
-                                igraph_vector_t* values, igraph_matrix_t* vectors) {
+static int igraph_i_arpack_rssolve_1x1(igraph_arpack_function_t *fun, void *extra,
+                                       igraph_arpack_options_t* options,
+                                       igraph_vector_t* values, igraph_matrix_t* vectors) {
     igraph_real_t a, b;
     int nev = options->nev;
 
@@ -294,9 +294,9 @@
  * "Solver" for 1x1 eigenvalue problems since ARPACK sometimes blows up with
  * these.
  */
-int igraph_i_arpack_rnsolve_1x1(igraph_arpack_function_t *fun, void *extra,
-                                igraph_arpack_options_t* options,
-                                igraph_matrix_t* values, igraph_matrix_t* vectors) {
+static int igraph_i_arpack_rnsolve_1x1(igraph_arpack_function_t *fun, void *extra,
+                                       igraph_arpack_options_t* options,
+                                       igraph_matrix_t* values, igraph_matrix_t* vectors) {
     igraph_real_t a, b;
     int nev = options->nev;
 
@@ -330,9 +330,9 @@
  * "Solver" for 2x2 nonsymmetric eigenvalue problems since ARPACK sometimes
  * blows up with these.
  */
-int igraph_i_arpack_rnsolve_2x2(igraph_arpack_function_t *fun, void *extra,
-                                igraph_arpack_options_t* options, igraph_matrix_t* values,
-                                igraph_matrix_t* vectors) {
+static int igraph_i_arpack_rnsolve_2x2(igraph_arpack_function_t *fun, void *extra,
+                                       igraph_arpack_options_t* options, igraph_matrix_t* values,
+                                       igraph_matrix_t* vectors) {
     igraph_real_t vec[2], mat[4];
     igraph_real_t a, b, c, d;
     igraph_real_t trace, det, tsq4_minus_d;
@@ -484,9 +484,9 @@
  * "Solver" for symmetric 2x2 eigenvalue problems since ARPACK sometimes blows
  * up with these.
  */
-int igraph_i_arpack_rssolve_2x2(igraph_arpack_function_t *fun, void *extra,
-                                igraph_arpack_options_t* options, igraph_vector_t* values,
-                                igraph_matrix_t* vectors) {
+static int igraph_i_arpack_rssolve_2x2(igraph_arpack_function_t *fun, void *extra,
+                                       igraph_arpack_options_t* options, igraph_vector_t* values,
+                                       igraph_matrix_t* vectors) {
     igraph_real_t vec[2], mat[4];
     igraph_real_t a, b, c, d;
     igraph_real_t trace, det, tsq4_minus_d;
@@ -778,7 +778,7 @@
  * \brief Tries to set up the value of \c ncv in an \c igraph_arpack_options_t
  *        automagically.
  */
-void igraph_i_arpack_auto_ncv(igraph_arpack_options_t* options) {
+static void igraph_i_arpack_auto_ncv(igraph_arpack_options_t* options) {
     /* This is similar to how Octave determines the value of ncv, with some
      * modifications. */
     int min_ncv = options->nev * 2 + 1;
@@ -811,7 +811,7 @@
  * \brief Prints a warning that informs the user that the ARPACK solver
  *        did not converge.
  */
-void igraph_i_arpack_report_no_convergence(const igraph_arpack_options_t* options) {
+static void igraph_i_arpack_report_no_convergence(const igraph_arpack_options_t* options) {
     char buf[1024];
     snprintf(buf, sizeof(buf), "ARPACK solver failed to converge (%d iterations, "
              "%d/%d eigenvectors converged)", options->iparam[2],
diff --git a/igraph/src/attributes.c b/igraph/src/attributes.c
--- a/igraph/src/attributes.c
+++ b/igraph/src/attributes.c
@@ -422,11 +422,7 @@
 
         type = (igraph_attribute_combination_type_t)va_arg(ap, int);
         if (type == IGRAPH_ATTRIBUTE_COMBINE_FUNCTION) {
-#if defined(__GNUC__)
-            func = va_arg(ap, void (*)(void));
-#else
-            func = va_arg(ap, void*);
-#endif
+            func = va_arg(ap, igraph_function_pointer_t);
         }
 
         if (strlen(name) == 0) {
diff --git a/igraph/src/bfgs.c b/igraph/src/bfgs.c
--- a/igraph/src/bfgs.c
+++ b/igraph/src/bfgs.c
@@ -24,7 +24,6 @@
 #include "igraph_nongraph.h"
 #include "igraph_interrupt_internal.h"
 #include "igraph_statusbar.h"
-#include "memory.h"
 #include "config.h"
 
 #include <math.h>
diff --git a/igraph/src/bignum.c b/igraph/src/bignum.c
--- a/igraph/src/bignum.c
+++ b/igraph/src/bignum.c
@@ -19,11 +19,10 @@
  *
  *  $Id: bignum.c,v 1.17 2005/07/23 02:55:53 pullmoll Exp $
  ******************************************************************************/
-#include <math.h>
+
 #include "bignum.h"
-#include "config.h"
-#include "math.h"
 #include "igraph_error.h"
+#include "config.h"
 
 #ifndef ASM_X86
     #ifdef  X86
diff --git a/igraph/src/bipartite.c b/igraph/src/bipartite.c
--- a/igraph/src/bipartite.c
+++ b/igraph/src/bipartite.c
@@ -150,11 +150,11 @@
     return 0;
 }
 
-int igraph_i_bipartite_projection(const igraph_t *graph,
-                                  const igraph_vector_bool_t *types,
-                                  igraph_t *proj,
-                                  int which,
-                                  igraph_vector_t *multiplicity) {
+static int igraph_i_bipartite_projection(const igraph_t *graph,
+                                         const igraph_vector_bool_t *types,
+                                         igraph_t *proj,
+                                         int which,
+                                         igraph_vector_t *multiplicity) {
 
     long int no_of_nodes = igraph_vcount(graph);
     long int i, j, k;
diff --git a/igraph/src/blas.c b/igraph/src/blas.c
--- a/igraph/src/blas.c
+++ b/igraph/src/blas.c
@@ -108,3 +108,20 @@
     int one = 1;
     return igraphdnrm2_(&n, VECTOR(*v), &one);
 }
+
+int igraph_blas_ddot(const igraph_vector_t *v1, const igraph_vector_t *v2,
+                       igraph_real_t *res) {
+
+    int n = igraph_vector_size(v1);
+    int one = 1;
+
+    if (igraph_vector_size(v2) != n) {
+        IGRAPH_ERROR("Dot product of vectors with different dimensions",
+                     IGRAPH_EINVAL);
+    }
+
+    *res = igraphddot_(&n, VECTOR(*v1), &one, VECTOR(*v2), &one);
+
+    return 0;
+}
+
diff --git a/igraph/src/bliss.cc b/igraph/src/bliss.cc
--- a/igraph/src/bliss.cc
+++ b/igraph/src/bliss.cc
@@ -25,6 +25,7 @@
 #include "igraph_datatype.h"
 #include "igraph_interface.h"
 
+#include "igraph_handle_exceptions.h"
 
 using namespace bliss;
 using namespace std;
@@ -53,7 +54,7 @@
 }
 
 
-void bliss_free_graph(AbstractGraph *g) {
+static void bliss_free_graph(AbstractGraph *g) {
     delete g;
 }
 
@@ -118,7 +119,7 @@
 
 // this is the callback function used with AbstractGraph::find_automorphisms()
 // it collects the group generators into a pointer vector
-void collect_generators(void *generators, unsigned int n, const unsigned int *aut) {
+static void collect_generators(void *generators, unsigned int n, const unsigned int *aut) {
     igraph_vector_ptr_t *gen = static_cast<igraph_vector_ptr_t *>(generators);
     igraph_vector_t *newvector = igraph_Calloc(1, igraph_vector_t);
     igraph_vector_init(newvector, n);
@@ -153,24 +154,27 @@
  */
 int igraph_canonical_permutation(const igraph_t *graph, const igraph_vector_int_t *colors,
                                  igraph_vector_t *labeling, igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {
-    AbstractGraph *g = bliss_from_igraph(graph);
-    IGRAPH_FINALLY(bliss_free_graph, g);
-    const unsigned int N = g->get_nof_vertices();
+    IGRAPH_HANDLE_EXCEPTIONS(
+        AbstractGraph *g = bliss_from_igraph(graph);
+        IGRAPH_FINALLY(bliss_free_graph, g);
+        const unsigned int N = g->get_nof_vertices();
 
-    IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));
-    IGRAPH_CHECK(bliss_set_colors(g, colors));
+        IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));
+        IGRAPH_CHECK(bliss_set_colors(g, colors));
 
-    Stats stats;
-    const unsigned int *cl = g->canonical_form(stats, NULL, NULL);
-    IGRAPH_CHECK(igraph_vector_resize(labeling, N));
-    for (unsigned int i = 0; i < N; i++) {
-        VECTOR(*labeling)[i] = cl[i];
-    }
+        Stats stats;
+        const unsigned int *cl = g->canonical_form(stats, NULL, NULL);
+        IGRAPH_CHECK(igraph_vector_resize(labeling, N));
+        for (unsigned int i = 0; i < N; i++) {
+            VECTOR(*labeling)[i] = cl[i];
+        }
 
-    bliss_info_to_igraph(info, stats);
+        bliss_info_to_igraph(info, stats);
 
-    delete g;
-    IGRAPH_FINALLY_CLEAN(1);
+        delete g;
+        IGRAPH_FINALLY_CLEAN(1);
+    );
+
     return IGRAPH_SUCCESS;
 }
 
@@ -199,19 +203,21 @@
  */
 int igraph_automorphisms(const igraph_t *graph, const igraph_vector_int_t *colors,
                          igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {
-    AbstractGraph *g = bliss_from_igraph(graph);
-    IGRAPH_FINALLY(bliss_free_graph, g);
+    IGRAPH_HANDLE_EXCEPTIONS(
+        AbstractGraph *g = bliss_from_igraph(graph);
+        IGRAPH_FINALLY(bliss_free_graph, g);
 
-    IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));
-    IGRAPH_CHECK(bliss_set_colors(g, colors));
+        IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));
+        IGRAPH_CHECK(bliss_set_colors(g, colors));
 
-    Stats stats;
-    g->find_automorphisms(stats, NULL, NULL);
+        Stats stats;
+        g->find_automorphisms(stats, NULL, NULL);
 
-    bliss_info_to_igraph(info, stats);
+        bliss_info_to_igraph(info, stats);
 
-    delete g;
-    IGRAPH_FINALLY_CLEAN(1);
+        delete g;
+        IGRAPH_FINALLY_CLEAN(1);
+    );
     return IGRAPH_SUCCESS;
 }
 
@@ -241,20 +247,23 @@
 int igraph_automorphism_group(
     const igraph_t *graph, const igraph_vector_int_t *colors, igraph_vector_ptr_t *generators,
     igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {
-    AbstractGraph *g = bliss_from_igraph(graph);
-    IGRAPH_FINALLY(bliss_free_graph, g);
+    IGRAPH_HANDLE_EXCEPTIONS(
+        AbstractGraph *g = bliss_from_igraph(graph);
+        IGRAPH_FINALLY(bliss_free_graph, g);
 
-    IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));
-    IGRAPH_CHECK(bliss_set_colors(g, colors));
+        IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));
+        IGRAPH_CHECK(bliss_set_colors(g, colors));
 
-    Stats stats;
-    igraph_vector_ptr_resize(generators, 0);
-    g->find_automorphisms(stats, collect_generators, generators);
+        Stats stats;
+        igraph_vector_ptr_resize(generators, 0);
+        g->find_automorphisms(stats, collect_generators, generators);
 
-    bliss_info_to_igraph(info, stats);
+        bliss_info_to_igraph(info, stats);
 
-    delete g;
-    IGRAPH_FINALLY_CLEAN(1);
+        delete g;
+        IGRAPH_FINALLY_CLEAN(1);
+    );
+
     return IGRAPH_SUCCESS;
 }
 
diff --git a/igraph/src/bliss_heap.cc b/igraph/src/bliss_heap.cc
--- a/igraph/src/bliss_heap.cc
+++ b/igraph/src/bliss_heap.cc
@@ -1,6 +1,6 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <limits.h>
+#include <cstdlib>
+//#include <stdio.h>
+#include <climits>
 #include "defs.hh"
 #include "heap.hh"
 
diff --git a/igraph/src/cattributes.c b/igraph/src/cattributes.c
--- a/igraph/src/cattributes.c
+++ b/igraph/src/cattributes.c
@@ -23,10 +23,10 @@
 
 #include "igraph_attributes.h"
 #include "igraph_memory.h"
-#include "config.h"
 #include "igraph_math.h"
 #include "igraph_interface.h"
 #include "igraph_random.h"
+#include "config.h"
 
 #include <string.h>
 
@@ -1577,7 +1577,8 @@
 
     igraph_free(funcs);
     igraph_free(TODO);
-    IGRAPH_FINALLY_CLEAN(2);
+    igraph_i_cattribute_permute_free(new_val);
+    IGRAPH_FINALLY_CLEAN(3);
 
     return 0;
 }
@@ -2187,7 +2188,7 @@
 
     igraph_free(funcs);
     igraph_free(TODO);
-    IGRAPH_FINALLY_CLEAN(2);
+    IGRAPH_FINALLY_CLEAN(3);
 
     return 0;
 }
@@ -2638,7 +2639,7 @@
  * is no attribute handler at all.</para>
  *
  * <para>The C attribute handler supports attaching real numbers and
- * character strings as attributes. No vectors are allowed, ie. every
+ * character strings as attributes. No vectors are allowed, i.e. every
  * vertex might have an attribute called <code>name</code>, but it is
  * not possible to have a <code>coords</code> graph (or other)
  * attribute which is a vector of numbers.</para>
@@ -3801,7 +3802,7 @@
         IGRAPH_FINALLY(igraph_free, log);
         rec->value = log;
         IGRAPH_CHECK(igraph_vector_bool_copy(log, v));
-        IGRAPH_FINALLY(igraph_vector_destroy, log);
+        IGRAPH_FINALLY(igraph_vector_bool_destroy, log);
         IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec));
         IGRAPH_FINALLY_CLEAN(4);
     }
@@ -3878,7 +3879,7 @@
 
 /**
  * \function igraph_cattribute_EAN_setv
- * Set a numeric edge attribute for all vertices.
+ * Set a numeric edge attribute for all edges.
  *
  * The attribute will be added if not present yet.
  * \param graph The graph.
@@ -3944,7 +3945,7 @@
 
 /**
  * \function igraph_cattribute_EAB_setv
- * Set a boolean edge attribute for all vertices.
+ * Set a boolean edge attribute for all edges.
  *
  * The attribute will be added if not present yet.
  * \param graph The graph.
@@ -4010,7 +4011,7 @@
 
 /**
  * \function igraph_cattribute_EAS_setv
- * Set a string edge attribute for all vertices.
+ * Set a string edge attribute for all edges.
  *
  * The attribute will be added if not present yet.
  * \param graph The graph.
diff --git a/igraph/src/centrality.c b/igraph/src/centrality.c
--- a/igraph/src/centrality.c
+++ b/igraph/src/centrality.c
@@ -22,9 +22,6 @@
 
 */
 
-#include <math.h>
-#include <string.h>    /* memset */
-#include <assert.h>
 #include "igraph_centrality.h"
 #include "igraph_math.h"
 #include "igraph_memory.h"
@@ -42,6 +39,9 @@
 #include "bigint.h"
 #include "prpack.h"
 
+#include <math.h>
+#include <string.h>    /* memset */
+
 int igraph_personalized_pagerank_arpack(const igraph_t *graph,
                                         igraph_vector_t *vector,
                                         igraph_real_t *value, const igraph_vs_t vids,
@@ -50,7 +50,7 @@
                                         const igraph_vector_t *weights,
                                         igraph_arpack_options_t *options);
 
-igraph_bool_t igraph_i_vector_mostly_negative(const igraph_vector_t *vector) {
+static igraph_bool_t igraph_i_vector_mostly_negative(const igraph_vector_t *vector) {
     /* Many of the centrality measures correspond to the eigenvector of some
      * matrix. When v is an eigenvector, c*v is also an eigenvector, therefore
      * it may happen that all the scores in the eigenvector are negative, in which
@@ -89,8 +89,8 @@
     return (mi < 1e-5) ? 1 : 0;
 }
 
-int igraph_i_eigenvector_centrality(igraph_real_t *to, const igraph_real_t *from,
-                                    int n, void *extra) {
+static int igraph_i_eigenvector_centrality(igraph_real_t *to, const igraph_real_t *from,
+                                           int n, void *extra) {
     igraph_adjlist_t *adjlist = extra;
     igraph_vector_int_t *neis;
     long int i, j, nlen;
@@ -115,8 +115,8 @@
     const igraph_vector_t *weights;
 } igraph_i_eigenvector_centrality_t;
 
-int igraph_i_eigenvector_centrality2(igraph_real_t *to, const igraph_real_t *from,
-                                     int n, void *extra) {
+static int igraph_i_eigenvector_centrality2(igraph_real_t *to, const igraph_real_t *from,
+                                            int n, void *extra) {
 
     igraph_i_eigenvector_centrality_t *data = extra;
     const igraph_t *graph = data->graph;
@@ -140,25 +140,6 @@
     return 0;
 }
 
-int igraph_i_eigenvector_centrality_loop(igraph_adjlist_t *adjlist) {
-
-    long int i, j, k, nlen, n = igraph_adjlist_size(adjlist);
-    igraph_vector_int_t *neis;
-
-    for (i = 0; i < n; i++) {
-        neis = igraph_adjlist_get(adjlist, i);
-        nlen = igraph_vector_int_size(neis);
-        for (j = 0; j < nlen && VECTOR(*neis)[j] < i; j++) ;
-        for (k = j; k < nlen && VECTOR(*neis)[k] == i; k++) ;
-        if (k != j) {
-            /* First loop edge is 'j', first non-loop edge is 'k' */
-            igraph_vector_int_remove_section(neis, j + (k - j) / 2, k);
-        }
-    }
-
-    return 0;
-}
-
 int igraph_eigenvector_centrality_undirected(const igraph_t *graph, igraph_vector_t *vector,
         igraph_real_t *value, igraph_bool_t scale,
         const igraph_vector_t *weights,
@@ -236,8 +217,6 @@
         IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
         IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
 
-        IGRAPH_CHECK(igraph_i_eigenvector_centrality_loop(&adjlist));
-
         IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_eigenvector_centrality,
                                            &adjlist, options, 0, &values, &vectors));
 
@@ -252,8 +231,6 @@
         IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL));
         IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
 
-        IGRAPH_CHECK(igraph_inclist_remove_duplicate(graph, &inclist));
-
         IGRAPH_CHECK(igraph_arpack_rssolve(igraph_i_eigenvector_centrality2,
                                            &data, options, 0, &values, &vectors));
 
@@ -504,21 +481,34 @@
  *
  * Eigenvector centrality is a measure of the importance of a node in a
  * network. It assigns relative scores to all nodes in the network based
- * on the principle that connections to high-scoring nodes contribute
- * more to the score of the node in question than equal connections to
- * low-scoring nodes. In practice, this is determined by calculating the
+ * on the principle that connections from high-scoring nodes contribute
+ * more to the score of the node in question than equal connections from
+ * low-scoring nodes. Specifically, the eigenvector centrality of each
+ * vertex is proportional to the sum of eigenvector centralities of its
+ * neighbors. In practice, the centralities are determined by calculating the
  * eigenvector corresponding to the largest positive eigenvalue of the
- * adjacency matrix. The centrality scores returned by igraph are always
- * normalized such that the largest eigenvector centrality score is one
- * (with one exception, see below).
+ * adjacency matrix. In the undirected case, this function considers
+ * the diagonal entries of the adjacency matrix to be \em twice the number of
+ * self-loops on the corresponding vertex.
  *
  * </para><para>
- * Since the eigenvector centrality scores of nodes in different components
- * do not affect each other, it may be beneficial for large graphs to
- * decompose it first into weakly connected components and calculate the
- * centrality scores individually for each component.
+ * The centrality scores returned by igraph can be normalized
+ * (using the \p scale parameter) such that the largest eigenvector centrality
+ * score is 1 (with one exception, see below).
  *
  * </para><para>
+ * In the directed case, the left eigenvector of the adjacency matrix is
+ * calculated. In other words, the centrality of a vertex is proportional
+ * to the sum of centralities of vertices pointing to it.
+ *
+ * </para><para>
+ * Eigenvector centrality is meaningful only for connected graphs.
+ * Graphs that are not connected should be decomposed into connected
+ * components, and the eigenvector centrality calculated for each separately.
+ * This function does not verify that the graph is connected. If it is not,
+ * in the undirected case the scores of all but one component will be zeros.
+ *
+ * </para><para>
  * Also note that the adjacency matrix of a directed acyclic graph or the
  * adjacency matrix of an empty graph does not possess positive eigenvalues,
  * therefore the eigenvector centrality is not defined for these graphs.
@@ -529,7 +519,7 @@
  * parameter, see below) and checking whether the eigenvalue is very close
  * to zero.
  *
- * \param graph The input graph. It might be directed.
+ * \param graph The input graph. It may be directed.
  * \param vector Pointer to an initialized vector, it will be resized
  *     as needed. The result of the computation is stored here. It can
  *     be a null pointer, then it is ignored.
@@ -591,9 +581,9 @@
 } igraph_i_kleinberg_data2_t;
 
 /* ARPACK auxiliary routine for the unweighted HITS algorithm */
-int igraph_i_kleinberg_unweighted(igraph_real_t *to,
-                                  const igraph_real_t *from,
-                                  int n, void *extra) {
+static int igraph_i_kleinberg_unweighted(igraph_real_t *to,
+                                         const igraph_real_t *from,
+                                         int n, void *extra) {
     igraph_i_kleinberg_data_t *data = (igraph_i_kleinberg_data_t*)extra;
     igraph_adjlist_t *in = data->in;
     igraph_adjlist_t *out = data->out;
@@ -625,9 +615,9 @@
 }
 
 /* ARPACK auxiliary routine for the weighted HITS algorithm */
-int igraph_i_kleinberg_weighted(igraph_real_t *to,
-                                const igraph_real_t *from,
-                                int n, void *extra) {
+static int igraph_i_kleinberg_weighted(igraph_real_t *to,
+                                       const igraph_real_t *from,
+                                       int n, void *extra) {
 
     igraph_i_kleinberg_data2_t *data = (igraph_i_kleinberg_data2_t*)extra;
     igraph_inclist_t *in = data->in;
@@ -663,10 +653,10 @@
     return 0;
 }
 
-int igraph_i_kleinberg(const igraph_t *graph, igraph_vector_t *vector,
-                       igraph_real_t *value, igraph_bool_t scale,
-                       const igraph_vector_t *weights,
-                       igraph_arpack_options_t *options, int inout) {
+static int igraph_i_kleinberg(const igraph_t *graph, igraph_vector_t *vector,
+                              igraph_real_t *value, igraph_bool_t scale,
+                              const igraph_vector_t *weights,
+                              igraph_arpack_options_t *options, int inout) {
 
     igraph_adjlist_t myinadjlist, myoutadjlist;
     igraph_inclist_t myininclist, myoutinclist;
@@ -934,8 +924,8 @@
     igraph_vector_t *reset;
 } igraph_i_pagerank_data2_t;
 
-int igraph_i_pagerank(igraph_real_t *to, const igraph_real_t *from,
-                      int n, void *extra) {
+static int igraph_i_pagerank(igraph_real_t *to, const igraph_real_t *from,
+                             int n, void *extra) {
 
     igraph_i_pagerank_data_t *data = extra;
     igraph_adjlist_t *adjlist = data->adjlist;
@@ -996,8 +986,8 @@
     return 0;
 }
 
-int igraph_i_pagerank2(igraph_real_t *to, const igraph_real_t *from,
-                       int n, void *extra) {
+static int igraph_i_pagerank2(igraph_real_t *to, const igraph_real_t *from,
+                              int n, void *extra) {
 
     igraph_i_pagerank_data2_t *data = extra;
     const igraph_t *graph = data->graph;
@@ -1608,7 +1598,8 @@
                                        nobigint);
 }
 
-int igraph_i_betweenness_estimate_weighted(const igraph_t *graph,
+static int igraph_i_betweenness_estimate_weighted(
+        const igraph_t *graph,
         igraph_vector_t *res,
         const igraph_vs_t vids,
         igraph_bool_t directed,
@@ -1678,11 +1669,18 @@
             igraph_vector_int_t *neis;
             long int nlen;
 
-            igraph_stack_push(&S, minnei);
-            if (cutoff > 0 && VECTOR(dist)[minnei] >= cutoff + 1.0) {
+            /* Ignore vertices that are more distant than the cutoff */
+            if (cutoff >= 0 && mindist > cutoff + 1.0) {
+                /* Reset variables if node is too distant */
+                VECTOR(tmpscore)[minnei] = 0;
+                VECTOR(dist)[minnei] = 0;
+                VECTOR(nrgeo)[minnei] = 0;
+                igraph_vector_int_clear(igraph_adjlist_get(&fathers, minnei));
                 continue;
             }
 
+            igraph_stack_push(&S, minnei);
+
             /* Now check all neighbors of 'minnei' for a shorter path */
             neis = igraph_inclist_get(&inclist, minnei);
             nlen = igraph_vector_int_size(neis);
@@ -1717,7 +1715,9 @@
 
                     VECTOR(dist)[to] = altdist;
                     IGRAPH_CHECK(igraph_2wheap_modify(&Q, to, -altdist));
-                } else if (cmp_result == 0) {
+                } else if (cmp_result == 0 &&
+                    (altdist <= cutoff + 1.0 || cutoff < 0)) {
+                    /* Only add if the node is not more distant than the cutoff */
                     igraph_vector_int_t *v = igraph_adjlist_get(&fathers, to);
                     igraph_vector_int_push_back(v, minnei);
                     VECTOR(nrgeo)[to] += VECTOR(nrgeo)[minnei];
@@ -1738,6 +1738,7 @@
                 VECTOR(*tmpres)[w] += VECTOR(tmpscore)[w];
             }
 
+            /* Reset variables */
             VECTOR(tmpscore)[w] = 0;
             VECTOR(dist)[w] = 0;
             VECTOR(nrgeo)[w] = 0;
@@ -1784,7 +1785,7 @@
     return 0;
 }
 
-void igraph_i_destroy_biguints(igraph_biguint_t *p) {
+static void igraph_i_destroy_biguints(igraph_biguint_t *p) {
     igraph_biguint_t *p2 = p;
     while ( *((long int*)(p)) ) {
         igraph_biguint_destroy(p);
@@ -1815,8 +1816,8 @@
  * \param directed Logical, if true directed paths will be considered
  *        for directed graphs. It is ignored for undirected graphs.
  * \param cutoff The maximal length of paths that will be considered.
- *        If zero or negative, the exact betweenness will be calculated
- *        (no upper limit on path lengths).
+ *        If negative or zero, the exact betweenness will be calculated, and
+ *        there will be no upper limit on path lengths.
  * \param weights An optional vector containing edge weights for
  *        calculating weighted betweenness. Supply a null pointer here
  *        for unweighted betweenness.
@@ -1866,6 +1867,11 @@
 
     igraph_biguint_t D, R, T;
 
+    /* Ensure that 0 is interpreted as infinity in the igraph 0.8 series. TODO: remove for 0.9. */
+    if (cutoff == 0) {
+        cutoff = -1;
+    }
+
     if (weights) {
         return igraph_i_betweenness_estimate_weighted(graph, res, vids, directed,
                 cutoff, weights, nobigint);
@@ -1956,12 +1962,22 @@
 
         while (!igraph_dqueue_empty(&q)) {
             long int actnode = (long int) igraph_dqueue_pop(&q);
-            IGRAPH_CHECK(igraph_stack_push(&stack, actnode));
 
-            if (cutoff > 0 && distance[actnode] >= cutoff + 1) {
+            /* Ignore vertices that are more distant than the cutoff */
+            if (cutoff >= 0 && distance[actnode] > cutoff + 1) {
+                /* Reset variables if node is too distant */
+                distance[actnode] = 0;
+                if (nobigint) {
+                    nrgeo[actnode] = 0;
+                } else {
+                    igraph_biguint_set_limb(&big_nrgeo[actnode], 0);
+                }
+                tmpscore[actnode] = 0;
+                igraph_vector_int_clear(igraph_adjlist_get(adjlist_in_p, actnode));
                 continue;
             }
 
+            IGRAPH_CHECK(igraph_stack_push(&stack, actnode));
             neis = igraph_adjlist_get(adjlist_out_p, actnode);
             nneis = igraph_vector_int_size(neis);
             for (j = 0; j < nneis; j++) {
@@ -1970,7 +1986,9 @@
                     distance[neighbor] = distance[actnode] + 1;
                     IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
                 }
-                if (distance[neighbor] == distance[actnode] + 1) {
+                if (distance[neighbor] == distance[actnode] + 1 &&
+                    (distance[neighbor] <= cutoff + 1 || cutoff < 0)) {
+                    /* Only add if the node is not more distant than the cutoff */
                     igraph_vector_int_t *v = igraph_adjlist_get(adjlist_in_p,
                                              neighbor);
                     igraph_vector_int_push_back(v, actnode);
@@ -2016,6 +2034,7 @@
                 VECTOR(*tmpres)[actnode] += tmpscore[actnode];
             }
 
+            /* Reset variables */
             distance[actnode] = 0;
             if (nobigint) {
                 nrgeo[actnode] = 0;
@@ -2079,7 +2098,8 @@
     return 0;
 }
 
-int igraph_i_edge_betweenness_estimate_weighted(const igraph_t *graph,
+static int igraph_i_edge_betweenness_estimate_weighted(
+        const igraph_t *graph,
         igraph_vector_t *result,
         igraph_bool_t directed,
         igraph_real_t cutoff,
@@ -2518,8 +2538,7 @@
  * \param graph The graph object.
  * \param res The result of the computation, a vector containing the
  *        closeness centrality scores for the given vertices.
- * \param vids Vector giving the vertices for which the closeness
- *        centrality scores will be computed.
+ * \param vids The vertices for which the closeness centrality will be computed.
  * \param mode The type of shortest paths to be used for the
  *        calculation in directed graphs. Possible values:
  *        \clist
@@ -2563,13 +2582,13 @@
                                      normalized);
 }
 
-int igraph_i_closeness_estimate_weighted(const igraph_t *graph,
-        igraph_vector_t *res,
-        const igraph_vs_t vids,
-        igraph_neimode_t mode,
-        igraph_real_t cutoff,
-        const igraph_vector_t *weights,
-        igraph_bool_t normalized) {
+static int igraph_i_closeness_estimate_weighted(const igraph_t *graph,
+                                                igraph_vector_t *res,
+                                                const igraph_vs_t vids,
+                                                igraph_neimode_t mode,
+                                                igraph_real_t cutoff,
+                                                const igraph_vector_t *weights,
+                                                igraph_bool_t normalized) {
 
     /* See igraph_shortest_paths_dijkstra() for the implementation
        details and the dirty tricks. */
@@ -2727,8 +2746,7 @@
  * \param graph The graph object.
  * \param res The result of the computation, a vector containing the
  *        closeness centrality scores for the given vertices.
- * \param vids Vector giving the vertices for which the closeness
- *        centrality scores will be computed.
+ * \param vids The vertices for which the closeness centrality will be estimated.
  * \param mode The type of shortest paths to be used for the
  *        calculation in directed graphs. Possible values:
  *        \clist
diff --git a/igraph/src/cliquer.c b/igraph/src/cliquer.c
--- a/igraph/src/cliquer.c
+++ b/igraph/src/cliquer.c
diff --git a/igraph/src/cliquer_graph.c b/igraph/src/cliquer_graph.c
--- a/igraph/src/cliquer_graph.c
+++ b/igraph/src/cliquer_graph.c
diff --git a/igraph/src/cliques.c b/igraph/src/cliques.c
--- a/igraph/src/cliques.c
+++ b/igraph/src/cliques.c
@@ -23,7 +23,6 @@
 
 #include "igraph_cliques.h"
 #include "igraph_memory.h"
-#include "igraph_random.h"
 #include "igraph_constants.h"
 #include "igraph_adjlist.h"
 #include "igraph_interrupt_internal.h"
@@ -37,7 +36,7 @@
 #include <assert.h>
 #include <string.h>    /* memset */
 
-void igraph_i_cliques_free_res(igraph_vector_ptr_t *res) {
+static void igraph_i_cliques_free_res(igraph_vector_ptr_t *res) {
     long i, n;
 
     n = igraph_vector_ptr_size(res);
@@ -50,14 +49,15 @@
     igraph_vector_ptr_clear(res);
 }
 
-int igraph_i_find_k_cliques(const igraph_t *graph,
-                            long int size,
-                            const igraph_real_t *member_storage,
-                            igraph_real_t **new_member_storage,
-                            long int old_clique_count,
-                            long int *clique_count,
-                            igraph_vector_t *neis,
-                            igraph_bool_t independent_vertices) {
+static int igraph_i_find_k_cliques(
+        const igraph_t *graph,
+        long int size,
+        const igraph_real_t *member_storage,
+        igraph_real_t **new_member_storage,
+        long int old_clique_count,
+        long int *clique_count,
+        igraph_vector_t *neis,
+        igraph_bool_t independent_vertices) {
 
     long int j, k, l, m, n, new_member_storage_size;
     const igraph_real_t *c1, *c2;
@@ -188,9 +188,9 @@
  * They are practically the same except that the complementer of the graph
  * should be used in the latter case.
  */
-int igraph_i_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,
-                     igraph_integer_t min_size, igraph_integer_t max_size,
-                     igraph_bool_t independent_vertices) {
+static int igraph_i_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,
+                            igraph_integer_t min_size, igraph_integer_t max_size,
+                            igraph_bool_t independent_vertices) {
 
     igraph_integer_t no_of_nodes;
     igraph_vector_t neis;
@@ -303,7 +303,7 @@
 
 /**
  * \function igraph_cliques
- * \brief Find all or some cliques in a graph
+ * \brief Finds all or some cliques in a graph.
  *
  * </para><para>
  * Cliques are fully connected subgraphs of a graph.
@@ -312,17 +312,13 @@
  * If you are only interested in the size of the largest clique in the graph,
  * use \ref igraph_clique_number() instead.
  *
- * </para><para>The current implementation of this function searches
- * for maximal independent vertex sets (see \ref
- * igraph_maximal_independent_vertex_sets()) in the complementer graph
- * using the algorithm published in:
- * S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm
- * for generating all the maximal independent sets. SIAM J Computing,
- * 6:505--517, 1977.
+ * </para><para>The current implementation of this function
+ * uses version 1.21 of the Cliquer library by Sampo Niskanen and
+ * Patric R. J. Östergård, http://users.aalto.fi/~pat/cliquer.html
  *
  * \param graph The input graph.
  * \param res Pointer to a pointer vector, the result will be stored
- *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   here, i.e. \p res will contain pointers to \ref igraph_vector_t
  *   objects which contain the indices of vertices involved in a clique.
  *   The pointer vector will be resized if needed but note that the
  *   objects in the pointer vector will not be freed.
@@ -334,7 +330,7 @@
  *
  * \sa \ref igraph_largest_cliques() and \ref igraph_clique_number().
  *
- * Time complexity: TODO
+ * Time complexity: Exponential
  *
  * \example examples/simple/igraph_cliques.c
  */
@@ -346,7 +342,7 @@
 
 /**
  * \function igraph_clique_size_hist
- * \brief Count cliques of each size in the graph
+ * \brief Counts cliques of each size in the graph.
  *
  * </para><para>
  * Cliques are fully connected subgraphs of a graph.
@@ -358,7 +354,7 @@
  * \param graph The input graph.
  * \param hist Pointer to an initialized vector. The result will be stored
  * here. The first element will store the number of size-1 cliques, the second
- * element the number of size-2 cliques, etc.  For cliques smaller than \c min_size,
+ * element the number of size-2 cliques, etc.  For cliques smaller than \p min_size,
  * zero counts will be returned.
  * \param min_size Integer giving the minimum size of the cliques to be
  *   returned. If negative or zero, no lower bound will be used.
@@ -385,7 +381,7 @@
  * Cliques are fully connected subgraphs of a graph. This function
  * enumerates all cliques within the given size range and calls
  * \p cliquehandler_fn for each of them. The cliques are passed to the
- * callback function as an <type>igraph_vector_t *</type>.  Destroying and
+ * callback function as a pointer to an \ref igraph_vector_t.  Destroying and
  * freeing this vector is left up to the user.  Use \ref igraph_vector_destroy()
  * to destroy it first, then free it using \ref igraph_free().
  *
@@ -399,7 +395,7 @@
  * \param max_size Integer giving the maximum size of the cliques to be
  *   returned. If negative or zero, no upper bound will be used.
  * \param cliquehandler_fn Callback function to be called for each clique.
- * See also igraph_clique_handler_t.
+ * See also \ref igraph_clique_handler_t.
  * \param arg Extra argument to supply to \p cliquehandler_fn.
  * \return Error code.
  *
@@ -417,7 +413,7 @@
 
 /**
  * \function igraph_weighted_cliques
- * \brief Find all cliques in a given weight range in a vertex weighted graph
+ * \brief Finds all cliques in a given weight range in a vertex weighted graph.
  *
  * </para><para>
  * Cliques are fully connected subgraphs of a graph.
@@ -434,7 +430,7 @@
  * \param vertex_weights A vector of vertex weights. The current implementation
  *   will truncate all weights to their integer parts.
  * \param res Pointer to a pointer vector, the result will be stored
- *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   here, i.e. \p res will contain pointers to \ref igraph_vector_t
  *   objects which contain the indices of vertices involved in a clique.
  *   The pointer vector will be resized if needed but note that the
  *   objects in the pointer vector will not be freed.
@@ -474,7 +470,7 @@
  * \param vertex_weights A vector of vertex weights. The current implementation
  *   will truncate all weights to their integer parts.
  * \param res Pointer to a pointer vector, the result will be stored
- *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   here, i.e. \p res will contain pointers to \ref igraph_vector_t
  *   objects which contain the indices of vertices involved in a clique.
  *   The pointer vector will be resized if needed but note that the
  *   objects in the pointer vector will not be freed.
@@ -492,7 +488,7 @@
 
 /**
  * \function igraph_weighted_clique_number
- * \brief Find the weight of the largest weight clique in the graph
+ * \brief Finds the weight of the largest weight clique in the graph.
  *
  * </para><para>The current implementation of this function
  * uses version 1.21 of the Cliquer library by Sampo Niskanen and
@@ -524,9 +520,10 @@
     igraph_integer_t max_size;
 } igraph_i_maximal_clique_data_t;
 
-int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data);
+static int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data);
 
-int igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph,
+static int igraph_i_maximal_or_largest_cliques_or_indsets(
+        const igraph_t *graph,
         igraph_vector_ptr_t *res,
         igraph_integer_t *clique_number,
         igraph_bool_t keep_only_largest,
@@ -534,7 +531,7 @@
 
 /**
  * \function igraph_independent_vertex_sets
- * \brief Find all independent vertex sets in a graph
+ * \brief Finds all independent vertex sets in a graph.
  *
  * </para><para>
  * A vertex set is considered independent if there are no edges between
@@ -553,7 +550,7 @@
  *
  * \param graph The input graph.
  * \param res Pointer to a pointer vector, the result will be stored
- *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   here, i.e. \p res will contain pointers to \ref igraph_vector_t
  *   objects which contain the indices of vertices involved in an independent
  *   vertex set. The pointer vector will be resized if needed but note that the
  *   objects in the pointer vector will not be freed.
@@ -619,7 +616,8 @@
     igraph_bool_t keep_only_largest;     /* True if we keep only the largest sets */
 } igraph_i_max_ind_vsets_data_t;
 
-int igraph_i_maximal_independent_vertex_sets_backtrack(const igraph_t *graph,
+static int igraph_i_maximal_independent_vertex_sets_backtrack(
+        const igraph_t *graph,
         igraph_vector_ptr_t *res,
         igraph_i_max_ind_vsets_data_t *clqdata,
         igraph_integer_t level) {
@@ -763,7 +761,7 @@
     return 0;
 }
 
-void igraph_i_free_set_array(igraph_set_t* array) {
+static void igraph_i_free_set_array(igraph_set_t* array) {
     long int i = 0;
     while (igraph_set_inited(array + i)) {
         igraph_set_destroy(array + i);
@@ -774,7 +772,7 @@
 
 /**
  * \function igraph_maximal_independent_vertex_sets
- * \brief Find all maximal independent vertex sets of a graph
+ * \brief Finds all maximal independent vertex sets of a graph.
  *
  * </para><para>
  * A maximal independent vertex set is an independent vertex set which
@@ -797,7 +795,7 @@
  *
  * \param graph The input graph.
  * \param res Pointer to a pointer vector, the result will be stored
- *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   here, i.e. \p res will contain pointers to \ref igraph_vector_t
  *   objects which contain the indices of vertices involved in an independent
  *   vertex set. The pointer vector will be resized if needed but note that the
  *   objects in the pointer vector will not be freed.
@@ -864,7 +862,7 @@
 
 /**
  * \function igraph_independence_number
- * \brief Find the independence number of the graph
+ * \brief Finds the independence number of the graph.
  *
  * </para><para>
  * The independence number of a graph is the cardinality of the largest
@@ -943,8 +941,8 @@
 /* MAXIMAL CLIQUES, LARGEST CLIQUES                                      */
 /*************************************************************************/
 
-int igraph_i_maximal_cliques_store_max_size(const igraph_vector_t* clique, void* data,
-        igraph_bool_t* cont) {
+static int igraph_i_maximal_cliques_store_max_size(const igraph_vector_t* clique, void* data,
+                                                   igraph_bool_t* cont) {
     igraph_integer_t* result = (igraph_integer_t*)data;
     IGRAPH_UNUSED(cont);
     if (*result < igraph_vector_size(clique)) {
@@ -953,7 +951,7 @@
     return IGRAPH_SUCCESS;
 }
 
-int igraph_i_maximal_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) {
+static int igraph_i_maximal_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) {
     igraph_vector_ptr_t* result = (igraph_vector_ptr_t*)data;
     igraph_vector_t* vec;
 
@@ -969,7 +967,7 @@
     return IGRAPH_SUCCESS;
 }
 
-int igraph_i_maximal_cliques_store_size_check(const igraph_vector_t* clique, void* data_, igraph_bool_t* cont) {
+static int igraph_i_maximal_cliques_store_size_check(const igraph_vector_t* clique, void* data_, igraph_bool_t* cont) {
     igraph_i_maximal_clique_data_t* data = (igraph_i_maximal_clique_data_t*)data_;
     igraph_vector_t* vec;
     igraph_integer_t size = (igraph_integer_t) igraph_vector_size(clique);
@@ -990,7 +988,7 @@
     return IGRAPH_SUCCESS;
 }
 
-int igraph_i_largest_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) {
+static int igraph_i_largest_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) {
     igraph_vector_ptr_t* result = (igraph_vector_ptr_t*)data;
     igraph_vector_t* vec;
     long int i, n;
@@ -1033,7 +1031,7 @@
  *
  * </para><para>
  * Note that this is not necessarily the same as a maximal clique,
- * ie. the largest cliques are always maximal but a maximal clique is
+ * i.e. the largest cliques are always maximal but a maximal clique is
  * not always largest.
  *
  * </para><para>The current implementation of this function searches
@@ -1066,7 +1064,7 @@
 
 /**
  * \function igraph_clique_number
- * \brief Find the clique number of the graph
+ * \brief Finds the clique number of the graph.
  *
  * </para><para>
  * The clique number of a graph is the size of the largest clique.
@@ -1091,13 +1089,13 @@
     igraph_vector_int_t cand_filtered;
 } igraph_i_maximal_cliques_stack_frame;
 
-void igraph_i_maximal_cliques_stack_frame_destroy(igraph_i_maximal_cliques_stack_frame *frame) {
+static void igraph_i_maximal_cliques_stack_frame_destroy(igraph_i_maximal_cliques_stack_frame *frame) {
     igraph_vector_int_destroy(&frame->cand);
     igraph_vector_int_destroy(&frame->fini);
     igraph_vector_int_destroy(&frame->cand_filtered);
 }
 
-void igraph_i_maximal_cliques_stack_destroy(igraph_stack_ptr_t *stack) {
+static void igraph_i_maximal_cliques_stack_destroy(igraph_stack_ptr_t *stack) {
     igraph_i_maximal_cliques_stack_frame *frame;
 
     while (!igraph_stack_ptr_empty(stack)) {
@@ -1109,7 +1107,7 @@
     igraph_stack_ptr_destroy(stack);
 }
 
-int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data) {
+static int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data) {
     int directed = igraph_is_directed(graph);
     long int i, j, k, l;
     igraph_integer_t no_of_nodes, nodes_to_check, nodes_done;
@@ -1331,7 +1329,7 @@
     return IGRAPH_SUCCESS;
 }
 
-int igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph,
+static int igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph,
         igraph_vector_ptr_t *res,
         igraph_integer_t *clique_number,
         igraph_bool_t keep_only_largest,
diff --git a/igraph/src/clustertool.cpp b/igraph/src/clustertool.cpp
--- a/igraph/src/clustertool.cpp
+++ b/igraph/src/clustertool.cpp
@@ -45,11 +45,6 @@
     #include <config.h>
 #endif
 
-#include <iostream>
-#include <cstdlib>
-#include <cstdio>
-#include <ctime>
-
 #include "NetDataTypes.h"
 #include "NetRoutines.h"
 #include "pottsmodel_2.h"
@@ -61,22 +56,25 @@
 #include "igraph_interface.h"
 #include "igraph_components.h"
 #include "igraph_interrupt_internal.h"
+#include "igraph_handle_exceptions.h"
 
-int igraph_i_community_spinglass_orig(const igraph_t *graph,
-                                      const igraph_vector_t *weights,
-                                      igraph_real_t *modularity,
-                                      igraph_real_t *temperature,
-                                      igraph_vector_t *membership,
-                                      igraph_vector_t *csize,
-                                      igraph_integer_t spins,
-                                      igraph_bool_t parupdate,
-                                      igraph_real_t starttemp,
-                                      igraph_real_t stoptemp,
-                                      igraph_real_t coolfact,
-                                      igraph_spincomm_update_t update_rule,
-                                      igraph_real_t gamma);
+static int igraph_i_community_spinglass_orig(
+        const igraph_t *graph,
+        const igraph_vector_t *weights,
+        igraph_real_t *modularity,
+        igraph_real_t *temperature,
+        igraph_vector_t *membership,
+        igraph_vector_t *csize,
+        igraph_integer_t spins,
+        igraph_bool_t parupdate,
+        igraph_real_t starttemp,
+        igraph_real_t stoptemp,
+        igraph_real_t coolfact,
+        igraph_spincomm_update_t update_rule,
+        igraph_real_t gamma);
 
-int igraph_i_community_spinglass_negative(const igraph_t *graph,
+static int igraph_i_community_spinglass_negative(
+        const igraph_t *graph,
         const igraph_vector_t *weights,
         igraph_real_t *modularity,
         igraph_real_t *temperature,
@@ -89,9 +87,9 @@
         igraph_real_t coolfact,
         igraph_spincomm_update_t update_rule,
         igraph_real_t gamma,
-        /*                    igraph_matrix_t *adhesion, */
-        /*                    igraph_matrix_t *normalised_adhesion, */
-        /*                    igraph_real_t *polarization, */
+        /* igraph_matrix_t *adhesion, */
+        /* igraph_matrix_t *normalised_adhesion, */
+        /* igraph_real_t *polarization, */
         igraph_real_t gamma_minus);
 
 /**
@@ -205,45 +203,47 @@
                                /*                 igraph_real_t *polarization, */
                                igraph_real_t gamma_minus) {
 
-    switch (implementation) {
-    case IGRAPH_SPINCOMM_IMP_ORIG:
-        return igraph_i_community_spinglass_orig(graph, weights, modularity,
-                temperature, membership, csize,
-                spins, parupdate, starttemp,
-                stoptemp, coolfact, update_rule,
-                gamma);
-        break;
-    case IGRAPH_SPINCOMM_IMP_NEG:
-        return igraph_i_community_spinglass_negative(graph, weights, modularity,
-                temperature, membership, csize,
-                spins, parupdate, starttemp,
-                stoptemp, coolfact,
-                update_rule, gamma,
-                /*                       adhesion, normalised_adhesion, */
-                /*                       polarization, */
-                gamma_minus);
-        break;
-    default:
-        IGRAPH_ERROR("Unknown `implementation' in spinglass community finding",
-                     IGRAPH_EINVAL);
-    }
-
+    IGRAPH_HANDLE_EXCEPTIONS(
+        switch (implementation) {
+        case IGRAPH_SPINCOMM_IMP_ORIG:
+            return igraph_i_community_spinglass_orig(graph, weights, modularity,
+                    temperature, membership, csize,
+                    spins, parupdate, starttemp,
+                    stoptemp, coolfact, update_rule,
+                    gamma);
+            break;
+        case IGRAPH_SPINCOMM_IMP_NEG:
+            return igraph_i_community_spinglass_negative(graph, weights, modularity,
+                    temperature, membership, csize,
+                    spins, parupdate, starttemp,
+                    stoptemp, coolfact,
+                    update_rule, gamma,
+                    /*                       adhesion, normalised_adhesion, */
+                    /*                       polarization, */
+                    gamma_minus);
+            break;
+        default:
+            IGRAPH_ERROR("Unknown `implementation' in spinglass community finding",
+                         IGRAPH_EINVAL);
+        }
+    );
     return 0;
 }
 
-int igraph_i_community_spinglass_orig(const igraph_t *graph,
-                                      const igraph_vector_t *weights,
-                                      igraph_real_t *modularity,
-                                      igraph_real_t *temperature,
-                                      igraph_vector_t *membership,
-                                      igraph_vector_t *csize,
-                                      igraph_integer_t spins,
-                                      igraph_bool_t parupdate,
-                                      igraph_real_t starttemp,
-                                      igraph_real_t stoptemp,
-                                      igraph_real_t coolfact,
-                                      igraph_spincomm_update_t update_rule,
-                                      igraph_real_t gamma) {
+static int igraph_i_community_spinglass_orig(
+        const igraph_t *graph,
+        const igraph_vector_t *weights,
+        igraph_real_t *modularity,
+        igraph_real_t *temperature,
+        igraph_vector_t *membership,
+        igraph_vector_t *csize,
+        igraph_integer_t spins,
+        igraph_bool_t parupdate,
+        igraph_real_t starttemp,
+        igraph_real_t stoptemp,
+        igraph_real_t coolfact,
+        igraph_spincomm_update_t update_rule,
+        igraph_real_t gamma) {
 
     unsigned long changes, runs;
     igraph_bool_t use_weights = 0;
@@ -448,94 +448,96 @@
                                       igraph_integer_t spins,
                                       igraph_spincomm_update_t update_rule,
                                       igraph_real_t gamma) {
-
-    igraph_bool_t use_weights = 0;
-    double prob;
-    ClusterList<NNode*> *cl_cur;
-    network *net;
-    PottsModel *pm;
-    char startnode[255];
+    IGRAPH_HANDLE_EXCEPTIONS(
+        igraph_bool_t use_weights = 0;
+        double prob;
+        ClusterList<NNode*> *cl_cur;
+        network *net;
+        PottsModel *pm;
+        char startnode[255];
 
-    /* Check arguments */
+        /* Check arguments */
 
-    if (spins < 2 || spins > 500) {
-        IGRAPH_ERROR("Invalid number of spins", IGRAPH_EINVAL);
-    }
-    if (update_rule != IGRAPH_SPINCOMM_UPDATE_SIMPLE &&
-        update_rule != IGRAPH_SPINCOMM_UPDATE_CONFIG) {
-        IGRAPH_ERROR("Invalid update rule", IGRAPH_EINVAL);
-    }
-    if (weights) {
-        if (igraph_vector_size(weights) != igraph_ecount(graph)) {
-            IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+        if (spins < 2 || spins > 500) {
+            IGRAPH_ERROR("Invalid number of spins", IGRAPH_EINVAL);
         }
-        use_weights = 1;
-    }
-    if (gamma < 0.0) {
-        IGRAPH_ERROR("Invalid gamme value", IGRAPH_EINVAL);
-    }
-    if (vertex < 0 || vertex > igraph_vcount(graph)) {
-        IGRAPH_ERROR("Invalid vertex id", IGRAPH_EINVAL);
-    }
+        if (update_rule != IGRAPH_SPINCOMM_UPDATE_SIMPLE &&
+            update_rule != IGRAPH_SPINCOMM_UPDATE_CONFIG) {
+            IGRAPH_ERROR("Invalid update rule", IGRAPH_EINVAL);
+        }
+        if (weights) {
+            if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+                IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+            }
+            use_weights = 1;
+        }
+        if (gamma < 0.0) {
+            IGRAPH_ERROR("Invalid gamme value", IGRAPH_EINVAL);
+        }
+        if (vertex < 0 || vertex > igraph_vcount(graph)) {
+            IGRAPH_ERROR("Invalid vertex id", IGRAPH_EINVAL);
+        }
 
-    /* Check whether we have a single component */
-    igraph_bool_t conn;
-    IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK));
-    if (!conn) {
-        IGRAPH_ERROR("Cannot work with unconnected graph", IGRAPH_EINVAL);
-    }
+        /* Check whether we have a single component */
+        igraph_bool_t conn;
+        IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK));
+        if (!conn) {
+            IGRAPH_ERROR("Cannot work with unconnected graph", IGRAPH_EINVAL);
+        }
 
-    net = new network;
-    net->node_list   = new DL_Indexed_List<NNode*>();
-    net->link_list   = new DL_Indexed_List<NLink*>();
-    net->cluster_list = new DL_Indexed_List<ClusterList<NNode*>*>();
+        net = new network;
+        net->node_list   = new DL_Indexed_List<NNode*>();
+        net->link_list   = new DL_Indexed_List<NLink*>();
+        net->cluster_list = new DL_Indexed_List<ClusterList<NNode*>*>();
 
-    /* Transform the igraph_t */
-    IGRAPH_CHECK(igraph_i_read_network(graph, weights,
-                                       net, use_weights, 0));
+        /* Transform the igraph_t */
+        IGRAPH_CHECK(igraph_i_read_network(graph, weights,
+                                           net, use_weights, 0));
 
-    prob = 2.0 * net->sum_weights / double(net->node_list->Size())
-           / double(net->node_list->Size() - 1);
+        prob = 2.0 * net->sum_weights / double(net->node_list->Size())
+               / double(net->node_list->Size() - 1);
 
-    pm = new PottsModel(net, (unsigned int)spins, update_rule);
+        pm = new PottsModel(net, (unsigned int)spins, update_rule);
 
-    /* initialize the random number generator */
-    RNG_BEGIN();
+        /* initialize the random number generator */
+        RNG_BEGIN();
 
-    /* to be exected, if we want to find the community around a particular node*/
-    /* the initial conf is needed, because otherwise,
-       the degree of the nodes is not in the weight property, stupid!!! */
-    pm->assign_initial_conf(-1);
-    snprintf(startnode, 255, "%li", (long int)vertex + 1);
-    pm->FindCommunityFromStart(gamma, prob, startnode, community,
-                               cohesion, adhesion, inner_links, outer_links);
+        /* to be exected, if we want to find the community around a particular node*/
+        /* the initial conf is needed, because otherwise,
+           the degree of the nodes is not in the weight property, stupid!!! */
+        pm->assign_initial_conf(-1);
+        snprintf(startnode, 255, "%li", (long int)vertex + 1);
+        pm->FindCommunityFromStart(gamma, prob, startnode, community,
+                                   cohesion, adhesion, inner_links, outer_links);
 
-    while (net->link_list->Size()) {
-        delete net->link_list->Pop();
-    }
-    while (net->node_list->Size()) {
-        delete net->node_list->Pop();
-    }
-    while (net->cluster_list->Size()) {
-        cl_cur = net->cluster_list->Pop();
-        while (cl_cur->Size()) {
-            cl_cur->Pop();
+        while (net->link_list->Size()) {
+            delete net->link_list->Pop();
         }
-        delete cl_cur;
-    }
-    delete net->link_list;
-    delete net->node_list;
-    delete net->cluster_list;
+        while (net->node_list->Size()) {
+            delete net->node_list->Pop();
+        }
+        while (net->cluster_list->Size()) {
+            cl_cur = net->cluster_list->Pop();
+            while (cl_cur->Size()) {
+                cl_cur->Pop();
+            }
+            delete cl_cur;
+        }
+        delete net->link_list;
+        delete net->node_list;
+        delete net->cluster_list;
 
-    RNG_END();
+        RNG_END();
 
-    delete net;
-    delete pm;
+        delete net;
+        delete pm;
+    );
 
     return 0;
 }
 
-int igraph_i_community_spinglass_negative(const igraph_t *graph,
+static int igraph_i_community_spinglass_negative(
+        const igraph_t *graph,
         const igraph_vector_t *weights,
         igraph_real_t *modularity,
         igraph_real_t *temperature,
@@ -548,9 +550,9 @@
         igraph_real_t coolfact,
         igraph_spincomm_update_t update_rule,
         igraph_real_t gamma,
-        /*                    igraph_matrix_t *adhesion, */
-        /*                    igraph_matrix_t *normalised_adhesion, */
-        /*                    igraph_real_t *polarization, */
+        /* igraph_matrix_t *adhesion, */
+        /* igraph_matrix_t *normalised_adhesion, */
+        /* igraph_real_t *polarization, */
         igraph_real_t gamma_minus) {
 
     unsigned long changes, runs;
diff --git a/igraph/src/cocitation.c b/igraph/src/cocitation.c
--- a/igraph/src/cocitation.c
+++ b/igraph/src/cocitation.c
@@ -254,13 +254,10 @@
     return 0;
 }
 
-int igraph_i_neisets_intersect(const igraph_vector_t *v1,
-                               const igraph_vector_t *v2, long int *len_union,
-                               long int *len_intersection);
 
-int igraph_i_neisets_intersect(const igraph_vector_t *v1,
-                               const igraph_vector_t *v2, long int *len_union,
-                               long int *len_intersection) {
+static int igraph_i_neisets_intersect(const igraph_vector_t *v1,
+                                      const igraph_vector_t *v2, long int *len_union,
+                                      long int *len_intersection) {
     /* ASSERT: v1 and v2 are sorted */
     long int i, j, i0, jj0;
     i0 = igraph_vector_size(v1); jj0 = igraph_vector_size(v2);
@@ -460,7 +457,7 @@
         if (seen == 0) {
             IGRAPH_ERROR("cannot calculate Jaccard similarity", IGRAPH_ENOMEM);
         }
-        IGRAPH_FINALLY(free, seen);
+        IGRAPH_FINALLY(igraph_free, seen);
 
         for (i = 0; i < k; i++) {
             j = (long int) VECTOR(*pairs)[i];
@@ -474,7 +471,7 @@
             }
         }
 
-        free(seen);
+        igraph_Free(seen);
         IGRAPH_FINALLY_CLEAN(1);
     }
 
diff --git a/igraph/src/cohesive_blocks.c b/igraph/src/cohesive_blocks.c
--- a/igraph/src/cohesive_blocks.c
+++ b/igraph/src/cohesive_blocks.c
@@ -27,13 +27,12 @@
 #include "igraph_flow.h"
 #include "igraph_separators.h"
 #include "igraph_structural.h"
-#include "igraph_components.h"
 #include "igraph_dqueue.h"
 #include "igraph_constructors.h"
 #include "igraph_interrupt_internal.h"
 #include "igraph_statusbar.h"
 
-void igraph_i_cohesive_blocks_free(igraph_vector_ptr_t *ptr) {
+static void igraph_i_cohesive_blocks_free(igraph_vector_ptr_t *ptr) {
     long int i, n = igraph_vector_ptr_size(ptr);
 
     for (i = 0; i < n; i++) {
@@ -45,7 +44,7 @@
     }
 }
 
-void igraph_i_cohesive_blocks_free2(igraph_vector_ptr_t *ptr) {
+static void igraph_i_cohesive_blocks_free2(igraph_vector_ptr_t *ptr) {
     long int i, n = igraph_vector_ptr_size(ptr);
 
     for (i = 0; i < n; i++) {
@@ -57,7 +56,7 @@
     }
 }
 
-void igraph_i_cohesive_blocks_free3(igraph_vector_ptr_t *ptr) {
+static void igraph_i_cohesive_blocks_free3(igraph_vector_ptr_t *ptr) {
     long int i, n = igraph_vector_ptr_size(ptr);
 
     for (i = 0; i < n; i++) {
@@ -75,14 +74,14 @@
  * all neighboring components.
  */
 
-int igraph_i_cb_components(igraph_t *graph,
-                           const igraph_vector_bool_t *excluded,
-                           igraph_vector_long_t *components,
-                           long int *no,
-                           /* working area follows */
-                           igraph_vector_long_t *compid,
-                           igraph_dqueue_t *Q,
-                           igraph_vector_t *neis) {
+static int igraph_i_cb_components(igraph_t *graph,
+                                  const igraph_vector_bool_t *excluded,
+                                  igraph_vector_long_t *components,
+                                  long int *no,
+                                  /* working area follows */
+                                  igraph_vector_long_t *compid,
+                                  igraph_dqueue_t *Q,
+                                  igraph_vector_t *neis) {
 
     long int no_of_nodes = igraph_vcount(graph);
     long int i;
@@ -137,8 +136,8 @@
     return 0;
 }
 
-igraph_bool_t igraph_i_cb_isin(const igraph_vector_t *needle,
-                               const igraph_vector_t *haystack) {
+static igraph_bool_t igraph_i_cb_isin(const igraph_vector_t *needle,
+                                      const igraph_vector_t *haystack) {
     long int nlen = igraph_vector_size(needle);
     long int hlen = igraph_vector_size(haystack);
     long int np = 0, hp = 0;
diff --git a/igraph/src/coloring.c b/igraph/src/coloring.c
--- a/igraph/src/coloring.c
+++ b/igraph/src/coloring.c
@@ -1,4 +1,23 @@
+/*
+  Heuristic graph coloring algorithms.
+  Copyright (C) 2017 Szabolcs Horvat <szhorvat@gmail.com>
 
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301 USA
+*/
+
 #include "igraph_coloring.h"
 #include "igraph_interface.h"
 #include "igraph_adjlist.h"
@@ -6,7 +25,7 @@
 #include "igraph_types_internal.h"
 
 
-int igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, igraph_vector_int_t *colors) {
+static int igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, igraph_vector_int_t *colors) {
     long i, vertex, maxdeg;
     long vc = igraph_vcount(graph);
     igraph_2wheap_t cn; /* indexed heap storing number of already coloured neighbours */
@@ -115,7 +134,7 @@
  * \brief Computes a vertex coloring using a greedy algorithm.
  *
  * </para><para>
- * This function assigns a "color"---represented as a non-negative integer---to
+ * This function assigns a "color"—represented as a non-negative integer—to
  * each vertex of the graph in such a way that neighboring vertices never have
  * the same color. The obtained coloring is not necessarily minimal.
  *
diff --git a/igraph/src/community.c b/igraph/src/community.c
--- a/igraph/src/community.c
+++ b/igraph/src/community.c
@@ -27,7 +27,6 @@
 #include "igraph_memory.h"
 #include "igraph_random.h"
 #include "igraph_arpack.h"
-#include "igraph_arpack_internal.h"
 #include "igraph_adjlist.h"
 #include "igraph_interface.h"
 #include "igraph_interrupt_internal.h"
@@ -50,7 +49,7 @@
     #include <R.h>
 #endif
 
-int igraph_i_rewrite_membership_vector(igraph_vector_t *membership) {
+static int igraph_i_rewrite_membership_vector(igraph_vector_t *membership) {
     long int no = (long int) igraph_vector_max(membership) + 1;
     igraph_vector_t idx;
     long int realno = 0;
@@ -73,13 +72,13 @@
     return 0;
 }
 
-int igraph_i_community_eb_get_merges2(const igraph_t *graph,
-                                      const igraph_vector_t *edges,
-                                      const igraph_vector_t *weights,
-                                      igraph_matrix_t *res,
-                                      igraph_vector_t *bridges,
-                                      igraph_vector_t *modularity,
-                                      igraph_vector_t *membership) {
+static int igraph_i_community_eb_get_merges2(const igraph_t *graph,
+                                             const igraph_vector_t *edges,
+                                             const igraph_vector_t *weights,
+                                             igraph_matrix_t *res,
+                                             igraph_vector_t *bridges,
+                                             igraph_vector_t *modularity,
+                                             igraph_vector_t *membership) {
 
     igraph_vector_t mymembership;
     long int no_of_nodes = igraph_vcount(graph);
@@ -177,7 +176,7 @@
 
 /**
  * \function igraph_community_eb_get_merges
- * \brief Calculating the merges, ie. the dendrogram for an edge betweenness community structure
+ * \brief Calculating the merges, i.e. the dendrogram for an edge betweenness community structure
  *
  * </para><para>
  * This function is handy if you have a sequence of edge which are
@@ -293,8 +292,8 @@
 }
 
 /* Find the smallest active element in the vector */
-long int igraph_i_vector_which_max_not_null(const igraph_vector_t *v,
-        const char *passive) {
+static long int igraph_i_vector_which_max_not_null(const igraph_vector_t *v,
+                                                   const char *passive) {
     long int which, i = 0, size = igraph_vector_size(v);
     igraph_real_t max;
     while (passive[i]) {
@@ -358,7 +357,7 @@
  * \param membership If not a null pointer, then the membership vector,
  *     corresponding to the highest modularity value, is stored here.
  * \param directed Logical constant, whether to calculate directed
- *    betweenness (ie. directed paths) for directed graphs. It is
+ *    betweenness (i.e. directed paths) for directed graphs. It is
  *    ignored for undirected graphs.
  * \param weights An optional vector containing edge weights. If null,
  *     the unweighted edge betweenness scores will be calculated and
@@ -482,7 +481,9 @@
     IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges));
     if (edge_betweenness) {
         IGRAPH_CHECK(igraph_vector_resize(edge_betweenness, no_of_edges));
-        VECTOR(*edge_betweenness)[no_of_edges - 1] = 0;
+        if (no_of_edges > 0) {
+            VECTOR(*edge_betweenness)[no_of_edges - 1] = 0;
+        }
     }
 
     IGRAPH_VECTOR_INIT_FINALLY(&eb, no_of_edges);
@@ -719,7 +720,7 @@
 
     if (result_owned) {
         igraph_vector_destroy(result);
-        free(result);
+        igraph_Free(result);
         IGRAPH_FINALLY_CLEAN(2);
     }
 
@@ -890,7 +891,7 @@
  * \param graph The input graph. It must be undirected; directed graphs are
  *     not supported yet.
  * \param membership Numeric vector which gives the type of each
- *     vertex, ie. the component to which it belongs.
+ *     vertex, i.e. the component to which it belongs.
  *     It does not have to be consecutive, i.e. empty communities are
  *     allowed.
  * \param modularity Pointer to a real number, the result will be
@@ -1052,7 +1053,7 @@
  * range 0, ..., n - 1.
  *
  * \param  membership  Numeric vector which gives the type of each
- *                     vertex, ie. the component to which it belongs.
+ *                     vertex, i.e. the component to which it belongs.
  *                     The vector will be altered in-place.
  * \param  new_to_old  Pointer to a vector which will contain the
  *                     old component ID for each new one, or NULL,
@@ -1176,9 +1177,9 @@
     igraph_real_t sumweights;
 } igraph_i_community_leading_eigenvector_data_t;
 
-int igraph_i_community_leading_eigenvector(igraph_real_t *to,
-        const igraph_real_t *from,
-        int n, void *extra) {
+static int igraph_i_community_leading_eigenvector(igraph_real_t *to,
+                                                  const igraph_real_t *from,
+                                                  int n, void *extra) {
 
     igraph_i_community_leading_eigenvector_data_t *data = extra;
     long int j, k, nlen, size = n;
@@ -1237,9 +1238,9 @@
     return 0;
 }
 
-int igraph_i_community_leading_eigenvector2(igraph_real_t *to,
-        const igraph_real_t *from,
-        int n, void *extra) {
+static int igraph_i_community_leading_eigenvector2(igraph_real_t *to,
+                                                   const igraph_real_t *from,
+                                                   int n, void *extra) {
 
     igraph_i_community_leading_eigenvector_data_t *data = extra;
     long int j, k, nlen, size = n;
@@ -1303,9 +1304,9 @@
     return 0;
 }
 
-int igraph_i_community_leading_eigenvector_weighted(igraph_real_t *to,
-        const igraph_real_t *from,
-        int n, void *extra) {
+static int igraph_i_community_leading_eigenvector_weighted(igraph_real_t *to,
+                                                           const igraph_real_t *from,
+                                                           int n, void *extra) {
 
     igraph_i_community_leading_eigenvector_data_t *data = extra;
     long int j, k, nlen, size = n;
@@ -1367,9 +1368,9 @@
     return 0;
 }
 
-int igraph_i_community_leading_eigenvector2_weighted(igraph_real_t *to,
-        const igraph_real_t *from,
-        int n, void *extra) {
+static int igraph_i_community_leading_eigenvector2_weighted(igraph_real_t *to,
+                                                            const igraph_real_t *from,
+                                                            int n, void *extra) {
 
     igraph_i_community_leading_eigenvector_data_t *data = extra;
     long int j, k, nlen, size = n;
@@ -1436,7 +1437,7 @@
     return 0;
 }
 
-void igraph_i_levc_free(igraph_vector_ptr_t *ptr) {
+static void igraph_i_levc_free(igraph_vector_ptr_t *ptr) {
     long int i, n = igraph_vector_ptr_size(ptr);
     for (i = 0; i < n; i++) {
         igraph_vector_t *v = VECTOR(*ptr)[i];
@@ -1447,8 +1448,8 @@
     }
 }
 
-void igraph_i_error_handler_none(const char *reason, const char *file,
-                                 int line, int igraph_errno) {
+static void igraph_i_error_handler_none(const char *reason, const char *file,
+                                        int line, int igraph_errno) {
     IGRAPH_UNUSED(reason);
     IGRAPH_UNUSED(file);
     IGRAPH_UNUSED(line);
@@ -1514,7 +1515,7 @@
  *    \ref igraph_vector_t object. The user is responsible of
  *    deallocating the memory that belongs to the individual vectors,
  *    by calling first \ref igraph_vector_destroy(), and then
- *    <code>free()</code> on them.
+ *    \ref igraph_free() on them.
  * \param history Pointer to an initialized vector or a null pointer.
  *    If not a null pointer, then a trace of the algorithm is stored
  *    here, encoded numerically. The various operations:
@@ -2682,7 +2683,7 @@
 } igraph_i_multilevel_community_list;
 
 /* Computes the modularity of a community partitioning */
-igraph_real_t igraph_i_multilevel_community_modularity(
+static igraph_real_t igraph_i_multilevel_community_modularity(
     const igraph_i_multilevel_community_list *communities) {
     igraph_real_t result = 0;
     long int i;
@@ -2703,7 +2704,7 @@
     long int id;
 } igraph_i_multilevel_link;
 
-int igraph_i_multilevel_link_cmp(const void *a, const void *b) {
+static int igraph_i_multilevel_link_cmp(const void *a, const void *b) {
     long int r = (((igraph_i_multilevel_link*)a)->from -
                   ((igraph_i_multilevel_link*)b)->from);
     if (r != 0) {
@@ -2715,7 +2716,7 @@
 }
 
 /* removes multiple edges and returns new edge id's for each edge in |E|log|E| */
-int igraph_i_multilevel_simplify_multiple(igraph_t *graph, igraph_vector_t *eids) {
+static int igraph_i_multilevel_simplify_multiple(igraph_t *graph, igraph_vector_t *eids) {
     long int ecount = igraph_ecount(graph);
     long int i, l = -1, last_from = -1, last_to = -1;
     igraph_bool_t directed = igraph_is_directed(graph);
@@ -2730,7 +2731,7 @@
     if (links == 0) {
         IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, links);
+    IGRAPH_FINALLY(igraph_free, links);
 
     for (i = 0; i < ecount; i++) {
         igraph_edge(graph, (igraph_integer_t) i, &from, &to);
@@ -2760,7 +2761,7 @@
         VECTOR(*eids)[links[i].id] = l;
     }
 
-    free(links);
+    igraph_Free(links);
     IGRAPH_FINALLY_CLEAN(1);
 
     igraph_destroy(graph);
@@ -2777,7 +2778,7 @@
     igraph_real_t weight;
 } igraph_i_multilevel_community_link;
 
-int igraph_i_multilevel_community_link_cmp(const void *a, const void *b) {
+static int igraph_i_multilevel_community_link_cmp(const void *a, const void *b) {
     return (int) (((igraph_i_multilevel_community_link*)a)->community -
                   ((igraph_i_multilevel_community_link*)b)->community);
 }
@@ -2795,11 +2796,12 @@
  *   communities incident on this vertex and the total weight of edges
  *   pointing to these communities
  */
-int igraph_i_multilevel_community_links(const igraph_t *graph,
-                                        const igraph_i_multilevel_community_list *communities,
-                                        igraph_integer_t vertex, igraph_vector_t *edges,
-                                        igraph_real_t *weight_all, igraph_real_t *weight_inside, igraph_real_t *weight_loop,
-                                        igraph_vector_t *links_community, igraph_vector_t *links_weight) {
+static int igraph_i_multilevel_community_links(
+        const igraph_t *graph,
+        const igraph_i_multilevel_community_list *communities,
+        igraph_integer_t vertex, igraph_vector_t *edges,
+        igraph_real_t *weight_all, igraph_real_t *weight_inside, igraph_real_t *weight_loop,
+        igraph_vector_t *links_community, igraph_vector_t *links_weight) {
 
     long int i, n, last = -1, c = -1;
     igraph_real_t weight = 1;
@@ -2869,10 +2871,10 @@
     return 0;
 }
 
-igraph_real_t igraph_i_multilevel_community_modularity_gain(
-    const igraph_i_multilevel_community_list *communities,
-    igraph_integer_t community, igraph_integer_t vertex,
-    igraph_real_t weight_all, igraph_real_t weight_inside) {
+static igraph_real_t igraph_i_multilevel_community_modularity_gain(
+        const igraph_i_multilevel_community_list *communities,
+        igraph_integer_t community, igraph_integer_t vertex,
+        igraph_real_t weight_all, igraph_real_t weight_inside) {
     IGRAPH_UNUSED(vertex);
     return weight_inside -
            communities->item[(long int)community].weight_all * weight_all / communities->weight_sum;
@@ -2884,7 +2886,7 @@
  * detection where a copy of the original graph is used anyway.
  * The membership vector will also be rewritten by the underlying
  * igraph_membership_reindex call */
-int igraph_i_multilevel_shrink(igraph_t *graph, igraph_vector_t *membership) {
+static int igraph_i_multilevel_shrink(igraph_t *graph, igraph_vector_t *membership) {
     igraph_vector_t edges;
     long int no_of_nodes = igraph_vcount(graph);
     long int no_of_edges = igraph_ecount(graph);
@@ -2955,9 +2957,11 @@
  *
  * Time complexity: in average near linear on sparse graphs.
  */
-int igraph_i_community_multilevel_step(igraph_t *graph,
-                                       igraph_vector_t *weights, igraph_vector_t *membership,
-                                       igraph_real_t *modularity) {
+static int igraph_i_community_multilevel_step(
+        igraph_t *graph,
+        igraph_vector_t *weights,
+        igraph_vector_t *membership,
+        igraph_real_t *modularity) {
 
     long int i, j;
     long int vcount = igraph_vcount(graph);
@@ -3316,15 +3320,15 @@
 }
 
 
-int igraph_i_compare_communities_vi(const igraph_vector_t *v1,
-                                    const igraph_vector_t *v2, igraph_real_t* result);
-int igraph_i_compare_communities_nmi(const igraph_vector_t *v1,
-                                     const igraph_vector_t *v2, igraph_real_t* result);
-int igraph_i_compare_communities_rand(const igraph_vector_t *v1,
-                                      const igraph_vector_t *v2, igraph_real_t* result, igraph_bool_t adjust);
-int igraph_i_split_join_distance(const igraph_vector_t *v1,
-                                 const igraph_vector_t *v2, igraph_integer_t* distance12,
-                                 igraph_integer_t* distance21);
+static int igraph_i_compare_communities_vi(const igraph_vector_t *v1,
+                                           const igraph_vector_t *v2, igraph_real_t* result);
+static int igraph_i_compare_communities_nmi(const igraph_vector_t *v1,
+                                            const igraph_vector_t *v2, igraph_real_t* result);
+static int igraph_i_compare_communities_rand(const igraph_vector_t *v1,
+                                             const igraph_vector_t *v2, igraph_real_t* result, igraph_bool_t adjust);
+static int igraph_i_split_join_distance(const igraph_vector_t *v1,
+                                        const igraph_vector_t *v2, igraph_integer_t* distance12,
+                                        igraph_integer_t* distance21);
 
 /**
  * \ingroup communities
@@ -3518,7 +3522,7 @@
  * membership vectors v1 and v2. This is needed by both Meila's and Danon's
  * community comparison measure.
  */
-int igraph_i_entropy_and_mutual_information(const igraph_vector_t* v1,
+static int igraph_i_entropy_and_mutual_information(const igraph_vector_t* v1,
         const igraph_vector_t* v2, double* h1, double* h2, double* mut_inf) {
     long int i, n = igraph_vector_size(v1);
     long int k1 = (long int)igraph_vector_max(v1) + 1;
@@ -3531,12 +3535,12 @@
     if (p1 == 0) {
         IGRAPH_ERROR("igraph_i_entropy_and_mutual_information failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, p1);
+    IGRAPH_FINALLY(igraph_free, p1);
     p2 = igraph_Calloc(k2, double);
     if (p2 == 0) {
         IGRAPH_ERROR("igraph_i_entropy_and_mutual_information failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, p2);
+    IGRAPH_FINALLY(igraph_free, p2);
 
     /* Calculate the entropy of v1 */
     *h1 = 0.0;
@@ -3584,7 +3588,7 @@
 
     igraph_spmatrix_iter_destroy(&mit);
     igraph_spmatrix_destroy(&m);
-    free(p1); free(p2);
+    igraph_Free(p1); igraph_Free(p2);
 
     IGRAPH_FINALLY_CLEAN(4);
 
@@ -3603,7 +3607,7 @@
  * </para><para>
  * Time complexity: O(n log(n))
  */
-int igraph_i_compare_communities_nmi(const igraph_vector_t *v1, const igraph_vector_t *v2,
+static int igraph_i_compare_communities_nmi(const igraph_vector_t *v1, const igraph_vector_t *v2,
                                      igraph_real_t* result) {
     double h1, h2, mut_inf;
 
@@ -3633,7 +3637,7 @@
  * </para><para>
  * Time complexity: O(n log(n))
  */
-int igraph_i_compare_communities_vi(const igraph_vector_t *v1, const igraph_vector_t *v2,
+static int igraph_i_compare_communities_vi(const igraph_vector_t *v1, const igraph_vector_t *v2,
                                     igraph_real_t* result) {
     double h1, h2, mut_inf;
 
@@ -3654,7 +3658,7 @@
  * Time complexity: O(n log(max(k1, k2))), where n is the number of vertices, k1
  * and k2 are the number of clusters in each of the clusterings.
  */
-int igraph_i_confusion_matrix(const igraph_vector_t *v1, const igraph_vector_t *v2,
+static int igraph_i_confusion_matrix(const igraph_vector_t *v1, const igraph_vector_t *v2,
                               igraph_spmatrix_t *m) {
     long int k1 = (long int)igraph_vector_max(v1) + 1;
     long int k2 = (long int)igraph_vector_max(v2) + 1;
@@ -3685,7 +3689,7 @@
  * Time complexity: O(n log(max(k1, k2))), where n is the number of vertices, k1
  * and k2 are the number of clusters in each of the clusterings.
  */
-int igraph_i_split_join_distance(const igraph_vector_t *v1, const igraph_vector_t *v2,
+static int igraph_i_split_join_distance(const igraph_vector_t *v1, const igraph_vector_t *v2,
                                  igraph_integer_t* distance12, igraph_integer_t* distance21) {
     long int n = igraph_vector_size(v1);
     igraph_vector_t rowmax, colmax;
@@ -3750,8 +3754,9 @@
  * Time complexity: O(n log(max(k1, k2))), where n is the number of vertices, k1
  * and k2 are the number of clusters in each of the clusterings.
  */
-int igraph_i_compare_communities_rand(const igraph_vector_t *v1,
-                                      const igraph_vector_t *v2, igraph_real_t *result, igraph_bool_t adjust) {
+static int igraph_i_compare_communities_rand(
+        const igraph_vector_t *v1, const igraph_vector_t *v2,
+        igraph_real_t *result, igraph_bool_t adjust) {
     igraph_spmatrix_t m;
     igraph_spmatrix_iter_t mit;
     igraph_vector_t rowsums, colsums;
diff --git a/igraph/src/community_leiden.c b/igraph/src/community_leiden.c
--- a/igraph/src/community_leiden.c
+++ b/igraph/src/community_leiden.c
@@ -46,7 +46,8 @@
  * and is updated in-place.
  *
  */
-int igraph_i_community_leiden_fastmovenodes(const igraph_t *graph,
+static int igraph_i_community_leiden_fastmovenodes(
+        const igraph_t *graph,
         const igraph_inclist_t *edges_per_node,
         const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,
         const igraph_real_t resolution_parameter,
@@ -121,7 +122,7 @@
         VECTOR(cluster_weights)[current_cluster] -= VECTOR(*node_weights)[v];
         VECTOR(nb_nodes_per_cluster)[current_cluster]--;
         if (VECTOR(nb_nodes_per_cluster)[current_cluster] == 0) {
-            igraph_stack_push(&empty_clusters, current_cluster);
+            IGRAPH_CHECK(igraph_stack_push(&empty_clusters, current_cluster));
         }
 
         /* Find out neighboring clusters */
@@ -136,12 +137,14 @@
         for (i = 0; i < degree; i++) {
             long int e = VECTOR(*edges)[i];
             long int u = (long int)IGRAPH_OTHER(graph, e, v);
-            c = VECTOR(*membership)[u];
-            if (!VECTOR(neighbor_cluster_added)[c]) {
-                VECTOR(neighbor_cluster_added)[c] = 1;
-                VECTOR(neighbor_clusters)[nb_neigh_clusters++] = c;
+            if (u != v) {
+                c = VECTOR(*membership)[u];
+                if (!VECTOR(neighbor_cluster_added)[c]) {
+                    VECTOR(neighbor_cluster_added)[c] = 1;
+                    VECTOR(neighbor_clusters)[nb_neigh_clusters++] = c;
+                }
+                VECTOR(edge_weights_per_cluster)[c] += VECTOR(*edge_weights)[e];
             }
-            VECTOR(edge_weights_per_cluster)[c] += VECTOR(*edge_weights)[e];
         }
 
         /* Calculate maximum diff */
@@ -176,7 +179,7 @@
                 long int e = VECTOR(*edges)[i];
                 long int u = (long int)IGRAPH_OTHER(graph, e, v);
                 if (VECTOR(node_is_stable)[u] && VECTOR(*membership)[u] != best_cluster) {
-                    igraph_dqueue_push(&unstable_nodes, u);
+                    IGRAPH_CHECK(igraph_dqueue_push(&unstable_nodes, u));
                     VECTOR(node_is_stable)[u] = 0;
                 }
             }
@@ -215,7 +218,10 @@
  * resulting \c nb_refined_clusters, then nodes in \c node_subset are numbered
  * C, C + 1, ..., C' - 1.
  */
-int igraph_i_community_leiden_clean_refined_membership(const igraph_vector_t* node_subset, igraph_vector_t *refined_membership, igraph_integer_t* nb_refined_clusters) {
+static int igraph_i_community_leiden_clean_refined_membership(
+        const igraph_vector_t* node_subset,
+        igraph_vector_t *refined_membership,
+        igraph_integer_t* nb_refined_clusters) {
     long int i, n = igraph_vector_size(node_subset);
     igraph_vector_t new_cluster;
 
@@ -280,7 +286,8 @@
  * igraph_i_community_leiden_clean_refined_membership for more information about
  * this aspect.
  */
-int igraph_i_community_leiden_mergenodes(const igraph_t *graph,
+static int igraph_i_community_leiden_mergenodes(
+        const igraph_t *graph,
         const igraph_inclist_t *edges_per_node,
         const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,
         const igraph_vector_t *node_subset,
@@ -324,7 +331,7 @@
         for (j = 0; j < degree; j++) {
             long int e = VECTOR(*edges)[j];
             long int u = (long int)IGRAPH_OTHER(graph, e, v);
-            if (VECTOR(*membership)[u] == cluster_subset) {
+            if (u != v && VECTOR(*membership)[u] == cluster_subset) {
                 VECTOR(external_edge_weight_per_cluster_in_subset)[i] += VECTOR(*edge_weights)[e];
             }
         }
@@ -378,7 +385,7 @@
             for (j = 0; j < degree; j++) {
                 long int e = (long int)VECTOR(*edges)[j];
                 long int u = (long int)IGRAPH_OTHER(graph, e, v);
-                if (VECTOR(*membership)[u] == cluster_subset) {
+                if (u != v && VECTOR(*membership)[u] == cluster_subset) {
                     long int c = VECTOR(*refined_membership)[u];
                     if (!VECTOR(neighbor_cluster_added)[c]) {
                         VECTOR(neighbor_cluster_added)[c] = 1;
@@ -420,7 +427,7 @@
             if (total_cum_trans_diff < IGRAPH_INFINITY) {
                 igraph_real_t r = igraph_rng_get_unif(igraph_rng_default(), 0, total_cum_trans_diff);
                 long int chosen_idx;
-                igraph_i_vector_binsearch_slice(&cum_trans_diff, r, &chosen_idx, 0, nb_neigh_clusters);
+                igraph_vector_binsearch_slice(&cum_trans_diff, r, &chosen_idx, 0, nb_neigh_clusters);
                 chosen_cluster = VECTOR(neighbor_clusters)[chosen_idx];
             } else {
                 chosen_cluster = best_cluster;
@@ -479,7 +486,7 @@
  * should be ensured that all clusters are always properly empty (or
  * non-existing) before calling this function.
  */
-int igraph_i_community_get_clusters(const igraph_vector_t *membership, igraph_vector_ptr_t *clusters) {
+static int igraph_i_community_get_clusters(const igraph_vector_t *membership, igraph_vector_ptr_t *clusters) {
     long int i, c, n = igraph_vector_size(membership);
     igraph_vector_t *cluster;
     for (i = 0; i < n; i++) {
@@ -498,7 +505,7 @@
         }
 
         /* Add node i to cluster vector */
-        igraph_vector_push_back(cluster, i);
+        IGRAPH_CHECK(igraph_vector_push_back(cluster, i));
     }
 
     return IGRAPH_SUCCESS;
@@ -518,7 +525,7 @@
  * aggregated_membership are all expected to be initialized.
  *
  */
-int igraph_i_community_leiden_aggregate(
+static int igraph_i_community_leiden_aggregate(
     const igraph_t *graph, const igraph_inclist_t *edges_per_node, const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,
     const igraph_vector_t *membership, const igraph_vector_t *refined_membership, const igraph_integer_t nb_refined_clusters,
     igraph_t *aggregated_graph, igraph_vector_t *aggregated_edge_weights, igraph_vector_t *aggregated_node_weights, igraph_vector_t *aggregated_membership) {
@@ -531,7 +538,7 @@
 
     /* Get refined clusters */
     IGRAPH_CHECK(igraph_vector_ptr_init(&refined_clusters, nb_refined_clusters));
-    igraph_vector_ptr_set_item_destructor(&refined_clusters, igraph_vector_destroy);
+    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&refined_clusters, igraph_vector_destroy);
     IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &refined_clusters);
     IGRAPH_CHECK(igraph_i_community_get_clusters(refined_membership, &refined_clusters));
 
@@ -591,10 +598,11 @@
             long int c2 = VECTOR(neighbor_clusters)[i];
 
             /* Add edge */
-            igraph_vector_push_back(&aggregated_edges, c); igraph_vector_push_back(&aggregated_edges, c2);
+            IGRAPH_CHECK(igraph_vector_push_back(&aggregated_edges, c));
+            IGRAPH_CHECK(igraph_vector_push_back(&aggregated_edges, c2));
 
             /* Add edge weight */
-            igraph_vector_push_back(aggregated_edge_weights, VECTOR(edge_weight_to_cluster)[c2]);
+            IGRAPH_CHECK(igraph_vector_push_back(aggregated_edge_weights, VECTOR(edge_weight_to_cluster)[c2]));
 
             VECTOR(edge_weight_to_cluster)[c2] = 0.0;
             VECTOR(neighbor_cluster_added)[c2] = 0;
@@ -604,17 +612,21 @@
 
     }
 
-    IGRAPH_CHECK(igraph_create(aggregated_graph, &aggregated_edges, nb_refined_clusters,
-                               IGRAPH_UNDIRECTED));
-
     igraph_vector_destroy(&neighbor_clusters);
     igraph_vector_bool_destroy(&neighbor_cluster_added);
     igraph_vector_destroy(&edge_weight_to_cluster);
-    igraph_vector_destroy(&aggregated_edges);
     igraph_vector_ptr_destroy_all(&refined_clusters);
 
-    IGRAPH_FINALLY_CLEAN(5);
+    IGRAPH_FINALLY_CLEAN(4);
 
+    igraph_destroy(aggregated_graph);
+    IGRAPH_CHECK(igraph_create(aggregated_graph, &aggregated_edges, nb_refined_clusters,
+                               IGRAPH_UNDIRECTED));
+
+    igraph_vector_destroy(&aggregated_edges);
+
+    IGRAPH_FINALLY_CLEAN(1);
+
     return IGRAPH_SUCCESS;
 }
 
@@ -641,9 +653,10 @@
  * weights inside cluster c. This is how the quality is calculated in practice.
  *
  */
-int igraph_i_community_leiden_quality(const igraph_t *graph, const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,
-                                      const igraph_vector_t *membership, const igraph_integer_t nb_comms, const igraph_real_t resolution_parameter,
-                                      igraph_real_t *quality) {
+static int igraph_i_community_leiden_quality(
+        const igraph_t *graph, const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,
+        const igraph_vector_t *membership, const igraph_integer_t nb_comms, const igraph_real_t resolution_parameter,
+        igraph_real_t *quality) {
     igraph_vector_t cluster_weights;
     igraph_real_t total_edge_weight = 0.0;
     igraph_eit_t eit;
@@ -697,13 +710,14 @@
  * partition for the aggregate network.
  */
 int igraph_i_community_leiden(const igraph_t *graph,
-                              const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,
+                              igraph_vector_t *edge_weights, igraph_vector_t *node_weights,
                               const igraph_real_t resolution_parameter, const igraph_real_t beta,
                               igraph_vector_t *membership, igraph_integer_t *nb_clusters, igraph_real_t *quality) {
     igraph_integer_t nb_refined_clusters;
     long int i, c, n = igraph_vcount(graph);
-    igraph_t *aggregated_graph, *tmp_graph;
-    igraph_vector_t *aggregated_edge_weights, *aggregated_node_weights, *aggregated_membership;
+    igraph_t aggregated_graph, *i_graph;
+    igraph_vector_t aggregated_edge_weights, aggregated_node_weights, aggregated_membership;
+    igraph_vector_t *i_edge_weights, *i_node_weights, *i_membership;
     igraph_vector_t tmp_edge_weights, tmp_node_weights, tmp_membership;
     igraph_vector_t refined_membership;
     igraph_vector_int_t aggregate_node;
@@ -722,8 +736,9 @@
 
     /* Initialize clusters */
     IGRAPH_CHECK(igraph_vector_ptr_init(&clusters, n));
-    igraph_vector_ptr_set_item_destructor(&clusters, igraph_vector_destroy);
+    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&clusters, igraph_vector_destroy);
     IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &clusters);
+
     /* Initialize aggregate nodes, which initially is identical to simply the
      * nodes in the graph. */
     IGRAPH_CHECK(igraph_vector_int_init(&aggregate_node, n));
@@ -732,18 +747,36 @@
         VECTOR(aggregate_node)[i] = i;
     }
 
+    /* Initialize refined membership */
     IGRAPH_CHECK(igraph_vector_init(&refined_membership, 0));
     IGRAPH_FINALLY(igraph_vector_destroy, &refined_membership);
 
-    /* Initialize aggregated graph, weights and membership. */
-    aggregated_graph = graph;
-    aggregated_edge_weights = edge_weights;
-    aggregated_node_weights = node_weights;
-    aggregated_membership = membership;
+    /* Initialize aggregated graph */
+    IGRAPH_CHECK(igraph_empty(&aggregated_graph, 0, IGRAPH_UNDIRECTED));
+    IGRAPH_FINALLY(igraph_destroy, &aggregated_graph);
 
+    /* Initialize aggregated edge weights */
+    IGRAPH_CHECK(igraph_vector_init(&aggregated_edge_weights, 0));
+    IGRAPH_FINALLY(igraph_vector_destroy, &aggregated_edge_weights);
+
+    /* Initialize aggregated node weights */
+    IGRAPH_CHECK(igraph_vector_init(&aggregated_node_weights, 0));
+    IGRAPH_FINALLY(igraph_vector_destroy, &aggregated_node_weights);
+
+    /* Initialize aggregated membership */
+    IGRAPH_CHECK(igraph_vector_init(&aggregated_membership, 0));
+    IGRAPH_FINALLY(igraph_vector_destroy, &aggregated_membership);
+
+    /* Set actual graph, weights and membership to be used. */
+    i_graph = (igraph_t*)graph;
+    i_edge_weights = edge_weights;
+    i_node_weights = node_weights;
+    i_membership = membership;
+
     /* Clean membership and count number of *clusters */
-    IGRAPH_CHECK(igraph_reindex_membership(aggregated_membership, NULL, nb_clusters));
 
+    IGRAPH_CHECK(igraph_reindex_membership(i_membership, NULL, nb_clusters));
+
     if (*nb_clusters > n) {
         IGRAPH_ERROR("Too many communities in membership vector", IGRAPH_EINVAL);
     }
@@ -751,45 +784,45 @@
     do {
 
         /* Get incidence list for fast iteration */
-        IGRAPH_CHECK(igraph_inclist_init(aggregated_graph, &edges_per_node, IGRAPH_ALL));
+        IGRAPH_CHECK(igraph_inclist_init( i_graph, &edges_per_node, IGRAPH_ALL));
         IGRAPH_FINALLY(igraph_inclist_destroy, &edges_per_node);
 
         /* Move around the nodes in order to increase the quality */
-        IGRAPH_CHECK(igraph_i_community_leiden_fastmovenodes(aggregated_graph,
+        IGRAPH_CHECK(igraph_i_community_leiden_fastmovenodes(i_graph,
                      &edges_per_node,
-                     aggregated_edge_weights, aggregated_node_weights,
+                     i_edge_weights, i_node_weights,
                      resolution_parameter,
                      nb_clusters,
-                     aggregated_membership));
+                     i_membership));
 
         /* We only continue clustering if not all clusters are represented by a
          * single node yet
          */
-        continue_clustering = (*nb_clusters < igraph_vcount(aggregated_graph));
+        continue_clustering = (*nb_clusters < igraph_vcount(i_graph));
 
         if (continue_clustering) {
             /* Set original membership */
             if (level > 0) {
                 for (i = 0; i < n; i++) {
                     long int v_aggregate = VECTOR(aggregate_node)[i];
-                    VECTOR(*membership)[i] = VECTOR(*aggregated_membership)[v_aggregate];
+                    VECTOR(*membership)[i] = VECTOR(*i_membership)[v_aggregate];
                 }
             }
 
             /* Get node sets for each cluster. */
-            IGRAPH_CHECK(igraph_i_community_get_clusters(aggregated_membership, &clusters));
+            IGRAPH_CHECK(igraph_i_community_get_clusters(i_membership, &clusters));
 
             /* Ensure refined membership is correct size */
-            IGRAPH_CHECK(igraph_vector_resize(&refined_membership, igraph_vcount(aggregated_graph)));
+            IGRAPH_CHECK(igraph_vector_resize(&refined_membership, igraph_vcount(i_graph)));
 
             /* Refine each cluster */
             nb_refined_clusters = 0;
             for (c = 0; c < *nb_clusters; c++) {
                 igraph_vector_t* cluster = (igraph_vector_t*)VECTOR(clusters)[c];
-                IGRAPH_CHECK(igraph_i_community_leiden_mergenodes(aggregated_graph,
+                IGRAPH_CHECK(igraph_i_community_leiden_mergenodes(i_graph,
                              &edges_per_node,
-                             aggregated_edge_weights, aggregated_node_weights,
-                             cluster, aggregated_membership, c,
+                             i_edge_weights, i_node_weights,
+                             cluster, i_membership, c,
                              resolution_parameter, beta,
                              &nb_refined_clusters, &refined_membership));
                 /* Empty cluster */
@@ -798,8 +831,9 @@
 
             /* If refinement didn't aggregate anything, we aggregate on the basis of
              * the actual clustering */
-            if (nb_refined_clusters >= igraph_vcount(aggregated_graph)) {
-                igraph_vector_update(&refined_membership, aggregated_membership);
+            if (nb_refined_clusters >= igraph_vcount(i_graph)) {
+                igraph_vector_update(&refined_membership, i_membership);
+                nb_refined_clusters = *nb_clusters;
             }
 
             /* Keep track of aggregate node. */
@@ -810,70 +844,27 @@
                 VECTOR(aggregate_node)[i] = (igraph_integer_t)VECTOR(refined_membership)[v_aggregate];
             }
 
-            /* Allocate temporary graph */
-            tmp_graph = igraph_Calloc(1, igraph_t);
-            if (tmp_graph == 0) {
-                IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for aggregate graph", IGRAPH_ENOMEM);
-            }
-            IGRAPH_FINALLY(free, tmp_graph);
-
             IGRAPH_CHECK(igraph_i_community_leiden_aggregate(
-                             aggregated_graph, &edges_per_node, aggregated_edge_weights, aggregated_node_weights,
-                             aggregated_membership, &refined_membership, nb_refined_clusters,
-                             tmp_graph, &tmp_edge_weights, &tmp_node_weights, &tmp_membership));
-
-            /* Graph has been created by aggregation, ensure it is properly destroyed if
-             * an error occurs. */
-            IGRAPH_FINALLY(igraph_destroy, tmp_graph);
-
-            if (level >= 1) {
-                /* Destroy previously allocated graph (note that aggregated_graph points to
-                 * the previously allocated tmp_graph). */
-                igraph_destroy(aggregated_graph);
-                igraph_Free(aggregated_graph);
-                IGRAPH_FINALLY_CLEAN(2);
-            }
+                             i_graph, &edges_per_node, i_edge_weights, i_node_weights,
+                             i_membership, &refined_membership, nb_refined_clusters,
+                             &aggregated_graph, &tmp_edge_weights, &tmp_node_weights, &tmp_membership));
 
             /* On the lowest level, the actual graph and node and edge weights and
-             * membership are used. On higher levels, we will have to use a new graph
-             * and node and edge weights to represent them. We perform the allocation
-             * of memory here. We only allocate the memory once, and simply update
-             * them in any subsequent rounds.
+             * membership are used. On higher levels, we will use the aggregated graph
+             * and associated vectors.
              */
             if (level == 0) {
-                aggregated_edge_weights = igraph_Calloc(1, igraph_vector_t);
-                if (aggregated_edge_weights == 0) {
-                    IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for aggregate edge weights", IGRAPH_ENOMEM);
-                }
-                IGRAPH_FINALLY(free, aggregated_edge_weights);
-                IGRAPH_CHECK(igraph_vector_init(aggregated_edge_weights, 0));
-                IGRAPH_FINALLY(igraph_vector_destroy, aggregated_edge_weights);
-
-                aggregated_node_weights = igraph_Calloc(1, igraph_vector_t);
-                if (aggregated_node_weights == 0) {
-                    IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for aggregate node weights", IGRAPH_ENOMEM);
-                }
-                IGRAPH_FINALLY(free, aggregated_node_weights);
-                IGRAPH_CHECK(igraph_vector_init(aggregated_node_weights, 0));
-                IGRAPH_FINALLY(igraph_vector_destroy, aggregated_node_weights);
-
-                aggregated_membership = igraph_Calloc(1, igraph_vector_t);
-                if (aggregated_membership == 0) {
-                    IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for aggregate membership", IGRAPH_ENOMEM);
-                }
-                IGRAPH_FINALLY(free, aggregated_membership);
-                IGRAPH_CHECK(igraph_vector_init(aggregated_membership, 0));
-                IGRAPH_FINALLY(igraph_vector_destroy, aggregated_membership);
+                /* Set actual graph, weights and membership to be used. */
+                i_graph = &aggregated_graph;
+                i_edge_weights = &aggregated_edge_weights;
+                i_node_weights = &aggregated_node_weights;
+                i_membership = &aggregated_membership;
             }
 
-            /* Set the aggregated graph correctly */
-            aggregated_graph = tmp_graph;
-
-            /* Update the aggregated administration. This does not allocate memory,
-             * it will always fit in existing memory allocated previously. */
-            igraph_vector_update(aggregated_edge_weights, &tmp_edge_weights);
-            igraph_vector_update(aggregated_node_weights, &tmp_node_weights);
-            igraph_vector_update(aggregated_membership, &tmp_membership);
+            /* Update the aggregated administration. */
+            IGRAPH_CHECK(igraph_vector_update(i_edge_weights, &tmp_edge_weights));
+            IGRAPH_CHECK(igraph_vector_update(i_node_weights, &tmp_node_weights));
+            IGRAPH_CHECK(igraph_vector_update(i_membership, &tmp_membership));
 
             level += 1;
         }
@@ -883,21 +874,12 @@
         IGRAPH_FINALLY_CLEAN(1);
     } while (continue_clustering);
 
-    /* If memory was allocated to represent the aggregated administration we need
-     * to make sure it is properly freed. This is only done if we have at least
-     * passed on to the next level of aggregation.
-     */
-    if (level > 0) {
-        igraph_destroy(aggregated_graph);
-        igraph_Free(aggregated_graph);
-        igraph_vector_destroy(aggregated_membership);
-        igraph_Free(aggregated_membership);
-        igraph_vector_destroy(aggregated_node_weights);
-        igraph_Free(aggregated_node_weights);
-        igraph_vector_destroy(aggregated_edge_weights);
-        igraph_Free(aggregated_edge_weights);
-        IGRAPH_FINALLY_CLEAN(8);
-    }
+    /* Free aggregated graph and associated vectors */
+    igraph_vector_destroy(&aggregated_membership);
+    igraph_vector_destroy(&aggregated_node_weights);
+    igraph_vector_destroy(&aggregated_edge_weights);
+    igraph_destroy(&aggregated_graph);
+    IGRAPH_FINALLY_CLEAN(4);
 
     /* Free remaining memory */
     igraph_vector_destroy(&refined_membership);
@@ -910,7 +892,7 @@
 
     /* Calculate quality */
     if (quality) {
-        igraph_i_community_leiden_quality(graph, edge_weights, node_weights, membership, *nb_clusters, resolution_parameter, quality);
+        IGRAPH_CHECK(igraph_i_community_leiden_quality(graph, edge_weights, node_weights, membership, *nb_clusters, resolution_parameter, quality));
     }
 
     return IGRAPH_SUCCESS;
@@ -924,7 +906,7 @@
  * This function implements the Leiden algorithm for finding community
  * structure, see Traag, V. A., Waltman, L., &amp; van Eck, N. J. (2019). From
  * Louvain to Leiden: guaranteeing well-connected communities. Scientific
- * reports, 9(1), 5233.  http://dx.doi.org/10.1038/s41598-019-41695-z.
+ * reports, 9(1), 5233. http://dx.doi.org/10.1038/s41598-019-41695-z
  *
  * </para><para>
  * It is similar to the multilevel algorithm, often called the Louvain
@@ -1002,7 +984,6 @@
                             const igraph_real_t resolution_parameter, const igraph_real_t beta, const igraph_bool_t start,
                             igraph_vector_t *membership, igraph_integer_t *nb_clusters, igraph_real_t *quality) {
     igraph_vector_t *i_edge_weights, *i_node_weights;
-    int ret;
     igraph_integer_t n = igraph_vcount(graph);
 
     if (start) {
@@ -1036,12 +1017,12 @@
         if (i_edge_weights == 0) {
             IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for edge weights", IGRAPH_ENOMEM);
         }
+        IGRAPH_FINALLY(igraph_free, i_edge_weights);
         IGRAPH_CHECK(igraph_vector_init(i_edge_weights, igraph_ecount(graph)));
-        IGRAPH_FINALLY(free, i_edge_weights);
         IGRAPH_FINALLY(igraph_vector_destroy, i_edge_weights);
         igraph_vector_fill(i_edge_weights, 1);
     } else {
-        i_edge_weights = edge_weights;
+        i_edge_weights = (igraph_vector_t*)edge_weights;
     }
 
     /* Check edge weights to possibly use default */
@@ -1050,18 +1031,18 @@
         if (i_node_weights == 0) {
             IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for node weights", IGRAPH_ENOMEM);
         }
+        IGRAPH_FINALLY(igraph_free, i_node_weights);
         IGRAPH_CHECK(igraph_vector_init(i_node_weights, n));
-        IGRAPH_FINALLY(free, i_node_weights);
         IGRAPH_FINALLY(igraph_vector_destroy, i_node_weights);
         igraph_vector_fill(i_node_weights, 1);
     } else {
-        i_node_weights = node_weights;
+        i_node_weights = (igraph_vector_t*)node_weights;
     }
 
     /* Perform actual Leiden algorithm */
-    ret = igraph_i_community_leiden(graph, i_edge_weights, i_node_weights,
-                                    resolution_parameter, beta,
-                                    membership, nb_clusters, quality);
+    IGRAPH_CHECK(igraph_i_community_leiden(graph, i_edge_weights, i_node_weights,
+                                           resolution_parameter, beta,
+                                           membership, nb_clusters, quality));
 
     if (!edge_weights) {
         igraph_vector_destroy(i_edge_weights);
@@ -1075,5 +1056,5 @@
         IGRAPH_FINALLY_CLEAN(2);
     }
 
-    return ret;
+    return IGRAPH_SUCCESS;
 }
diff --git a/igraph/src/components.c b/igraph/src/components.c
--- a/igraph/src/components.c
+++ b/igraph/src/components.c
@@ -32,7 +32,6 @@
 #include "igraph_stack.h"
 #include "igraph_vector.h"
 #include "config.h"
-#include <string.h>
 #include <limits.h>
 
 static int igraph_i_clusters_weak(const igraph_t *graph, igraph_vector_t *membership,
@@ -410,7 +409,7 @@
     if (already_added == 0) {
         IGRAPH_ERROR("is connected (weak) failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, already_added); /* TODO: hack */
+    IGRAPH_FINALLY(igraph_free, already_added);
 
     IGRAPH_DQUEUE_INIT_FINALLY(&q, 10);
     IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
@@ -616,7 +615,7 @@
     igraph_vector_destroy(&neis);
     igraph_vector_destroy(&verts);
     igraph_dqueue_destroy(&q);
-    igraph_free(already_added);
+    igraph_Free(already_added);
     IGRAPH_FINALLY_CLEAN(5);  /* + components */
 
     return 0;
@@ -877,7 +876,7 @@
  * components.
  *
  * </para><para>
- * Somewhat arbitrarily, igraph does not consider comppnents containing
+ * Somewhat arbitrarily, igraph does not consider components containing
  * a single vertex only as being biconnected. Isolated vertices will
  * not be part of any of the biconnected components.
  *
@@ -889,7 +888,7 @@
  *     a spanning tree of the biconnected component is returned.
  *     Note you'll have to
  *     destroy each vector first by calling \ref igraph_vector_destroy()
- *     and then <code>free()</code> on it, plus you need to call
+ *     and then \ref igraph_free() on it, plus you need to call
  *     \ref igraph_vector_ptr_destroy() on the list to regain all
  *     allocated memory.
  * \param component_edges If not a NULL pointer, then the edges of the
@@ -1146,9 +1145,15 @@
 
 
 /* igraph_bridges -- find all bridges in the graph */
-/* based on https://www.geeksforgeeks.org/bridge-in-a-graph/ */
+/* The algorithm is based on https://www.geeksforgeeks.org/bridge-in-a-graph/
+   but instead of keeping track of the parent of each vertex in the DFS tree
+   we keep track of its incoming edge. This is necessary to support multigraphs. */
 
-static int igraph_i_bridges_rec(const igraph_t *graph, const igraph_inclist_t *il, igraph_integer_t u, igraph_integer_t *time, igraph_vector_t *bridges, igraph_vector_bool_t *visited, igraph_vector_int_t *disc, igraph_vector_int_t *low, igraph_vector_int_t *parent) {
+static int igraph_i_bridges_rec(
+        const igraph_t *graph, const igraph_inclist_t *il, igraph_integer_t u,
+        igraph_integer_t *time, igraph_vector_t *bridges, igraph_vector_bool_t *visited,
+        igraph_vector_int_t *disc, igraph_vector_int_t *low, igraph_vector_int_t *incoming_edge)
+{
     igraph_vector_int_t *incedges;
     long nc; /* neighbour count */
     long i;
@@ -1167,15 +1172,15 @@
         igraph_integer_t v = IGRAPH_TO(graph, edge) == u ? IGRAPH_FROM(graph, edge) : IGRAPH_TO(graph, edge);
 
         if (! VECTOR(*visited)[v]) {
-            VECTOR(*parent)[v] = u;
-            IGRAPH_CHECK(igraph_i_bridges_rec(graph, il, v, time, bridges, visited, disc, low, parent));
+            VECTOR(*incoming_edge)[v] = edge;
+            IGRAPH_CHECK(igraph_i_bridges_rec(graph, il, v, time, bridges, visited, disc, low, incoming_edge));
 
             VECTOR(*low)[u] = VECTOR(*low)[u] < VECTOR(*low)[v] ? VECTOR(*low)[u] : VECTOR(*low)[v];
 
             if (VECTOR(*low)[v] > VECTOR(*disc)[u]) {
                 IGRAPH_CHECK(igraph_vector_push_back(bridges, edge));
             }
-        } else if (v != VECTOR(*parent)[u]) {
+        } else if (edge != VECTOR(*incoming_edge)[u]) {
             VECTOR(*low)[u] = VECTOR(*low)[u] < VECTOR(*disc)[v] ? VECTOR(*low)[u] : VECTOR(*disc)[v];
         }
     }
@@ -1204,7 +1209,7 @@
     igraph_inclist_t il;
     igraph_vector_bool_t visited;
     igraph_vector_int_t disc, low;
-    igraph_vector_int_t parent;
+    igraph_vector_int_t incoming_edge;
     long n;
     long i;
     igraph_integer_t time;
@@ -1223,10 +1228,10 @@
     IGRAPH_CHECK(igraph_vector_int_init(&low, n));
     IGRAPH_FINALLY(igraph_vector_int_destroy, &low);
 
-    IGRAPH_CHECK(igraph_vector_int_init(&parent, n));
-    IGRAPH_FINALLY(igraph_vector_int_destroy, &parent);
+    IGRAPH_CHECK(igraph_vector_int_init(&incoming_edge, n));
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &incoming_edge);
     for (i = 0; i < n; ++i) {
-        VECTOR(parent)[i] = -1;
+        VECTOR(incoming_edge)[i] = -1;
     }
 
     igraph_vector_clear(bridges);
@@ -1234,10 +1239,10 @@
     time = 0;
     for (i = 0; i < n; ++i)
         if (! VECTOR(visited)[i]) {
-            IGRAPH_CHECK(igraph_i_bridges_rec(graph, &il, i, &time, bridges, &visited, &disc, &low, &parent));
+            IGRAPH_CHECK(igraph_i_bridges_rec(graph, &il, i, &time, bridges, &visited, &disc, &low, &incoming_edge));
         }
 
-    igraph_vector_int_destroy(&parent);
+    igraph_vector_int_destroy(&incoming_edge);
     igraph_vector_int_destroy(&low);
     igraph_vector_int_destroy(&disc);
     igraph_vector_bool_destroy(&visited);
diff --git a/igraph/src/conversion.c b/igraph/src/conversion.c
--- a/igraph/src/conversion.c
+++ b/igraph/src/conversion.c
@@ -37,8 +37,8 @@
  * \brief Returns the adjacency matrix of a graph
  *
  * </para><para>
- * The result is an incidence matrix, it contains numbers greater
- * than one if there are multiple edges in the graph.
+ * The result is an adjacency matrix. Entry i, j of the matrix
+ * contains the number of edges connecting vertex i to vertex j.
  * \param graph Pointer to the graph to convert
  * \param res Pointer to an initialized matrix object, it will be
  *        resized if needed.
@@ -172,8 +172,8 @@
  * \brief Returns the adjacency matrix of a graph in sparse matrix format
  *
  * </para><para>
- * The result is an incidence matrix, it contains numbers greater
- * than one if there are multiple edges in the graph.
+ * The result is an adjacency matrix. Entry i, j of the matrix
+ * contains the number of edges connecting vertex i to vertex j.
  * \param graph Pointer to the graph to convert
  * \param res Pointer to an initialized sparse matrix object, it will be
  *        resized if needed.
@@ -782,8 +782,6 @@
 
     return 0;
 }
-int igraph_i_normalize_sparsemat(igraph_sparsemat_t *sparsemat,
-                                 igraph_bool_t column_wise);
 
 
 int igraph_i_normalize_sparsemat(igraph_sparsemat_t *sparsemat,
diff --git a/igraph/src/defs.cc b/igraph/src/defs.cc
--- a/igraph/src/defs.cc
+++ b/igraph/src/defs.cc
@@ -1,5 +1,6 @@
 #include <cstdlib>
 #include <cstdio>
+#include <stdexcept>
 #include "defs.hh"
 
 /*
@@ -23,20 +24,17 @@
 
 namespace bliss {
 
-#ifndef USING_R
-
 void
 fatal_error(const char* fmt, ...)
 {
+  char buffer[1024];
   va_list ap;
   va_start(ap, fmt);
-  fprintf(stderr,"Bliss fatal error: ");
-  vfprintf(stderr, fmt, ap);
-  fprintf(stderr, "\nAborting!\n");
+  sprintf(buffer, "Bliss fatal error: ");
+  vsprintf(buffer, fmt, ap);
+  throw std::runtime_error(buffer);
   va_end(ap);
   exit(1);
 }
-
-#endif
 
 }
diff --git a/igraph/src/degree_sequence.cpp b/igraph/src/degree_sequence.cpp
--- a/igraph/src/degree_sequence.cpp
+++ b/igraph/src/degree_sequence.cpp
@@ -1,6 +1,6 @@
 /*
   Constructing realizations of degree sequences and bi-degree sequences.
-  Copyright (C) 2018 Szabolcs Horvat <szhorvat@gmail.com>
+  Copyright (C) 2018-2020 Szabolcs Horvat <szhorvat@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -82,10 +82,6 @@
         vd_pair vd = vertices.back();
         vertices.pop_back();
 
-        if (vd.degree < 0) {
-            IGRAPH_ERROR("Vertex degrees must be positive", IGRAPH_EINVAL);
-        }
-
         if (vd.degree == 0) {
             continue;
         }
@@ -148,10 +144,6 @@
         vd_pair vd = **pt;
         vertices.erase(*pt);
 
-        if (vd.degree < 0) {
-            IGRAPH_ERROR("Vertex degrees must be positive", IGRAPH_EINVAL);
-        }
-
         if (vd.degree == 0) {
             continue;
         }
@@ -226,12 +218,8 @@
         }
 
 
-        if (vdp->degree.first < 0 || vdp->degree.second < 0) {
-            IGRAPH_ERROR("Vertex degrees must be positive", IGRAPH_EINVAL);
-        }
-
         // are there a sufficient number of other vertices to connect to?
-        if (vertices.size() < vdp->degree.second - 1) {
+        if (vertices.size() - 1 < vdp->degree.second) {
             goto fail;
         }
 
@@ -294,10 +282,6 @@
             continue;
         }
 
-        if (vd.degree.first < 0 || vd.degree.second < 0) {
-            IGRAPH_ERROR("Vertex degrees must be positive", IGRAPH_EINVAL);
-        }
-
         int k = 0;
         vlist::iterator it;
         for (it = vertices.begin();
@@ -342,6 +326,10 @@
         IGRAPH_ERROR("The sum of degrees must be even for an undirected graph", IGRAPH_EINVAL);
     }
 
+    if (igraph_vector_min(deg) < 0) {
+        IGRAPH_ERROR("Vertex degrees must be non-negative", IGRAPH_EINVAL);
+    }
+
     igraph_vector_t edges;
     IGRAPH_CHECK(igraph_vector_init(&edges, deg_sum));
     IGRAPH_FINALLY(igraph_vector_destroy, &edges);
@@ -384,6 +372,10 @@
         IGRAPH_ERROR("In- and out-degree sequences do not sum to the same value", IGRAPH_EINVAL);
     }
 
+    if (igraph_vector_min(outdeg) < 0 || igraph_vector_min(indeg) < 0) {
+        IGRAPH_ERROR("Vertex degrees must be non-negative", IGRAPH_EINVAL);
+    }
+
     igraph_vector_t edges;
     IGRAPH_CHECK(igraph_vector_init(&edges, 2 * edge_count));
     IGRAPH_FINALLY(igraph_vector_destroy, &edges);
@@ -426,6 +418,32 @@
  *
  * The \c method parameter controls the order in which the vertices to be connected are chosen.
  *
+ * </para><para>
+ * References:
+ *
+ * </para><para>
+ * V. Havel,
+ * Poznámka o existenci konečných grafů (A remark on the existence of finite graphs),
+ * Časopis pro pěstování matematiky 80, 477-480 (1955).
+ * http://eudml.org/doc/19050
+ *
+ * </para><para>
+ * S. L. Hakimi,
+ * On Realizability of a Set of Integers as Degrees of the Vertices of a Linear Graph,
+ * Journal of the SIAM 10, 3 (1962).
+ * https://www.jstor.org/stable/2098746
+ *
+ * </para><para>
+ * D. J. Kleitman and D. L. Wang,
+ * Algorithms for Constructing Graphs and Digraphs with Given Valences and Factors,
+ * Discrete Mathematics 6, 1 (1973).
+ * https://doi.org/10.1016/0012-365X%2873%2990037-X
+ *
+ * </para><para>
+ * Sz. Horvát and C. D. Modes,
+ * Connectivity matters: Construction and exact random sampling of connected graphs (2020).
+ * https://arxiv.org/abs/2009.03747
+ *
  * \param graph Pointer to an uninitialized graph object.
  * \param outdeg The degree sequence for a simple undirected graph
  *        (if \p indeg is NULL or of length zero), or the out-degree sequence of
@@ -438,8 +456,8 @@
  *          The vertex with smallest remaining degree is selected first. The result is usually
  *          a graph with high negative degree assortativity. In the undirected case, this method
  *          is guaranteed to generate a connected graph, provided that a connected realization exists.
- *          See http://szhorvat.net/pelican/hh-connected-graphs.html for a proof.
- *          In the directed case it tends to generate weakly connected graphs, but this is not
+ *          See Horvát and Modes (2020) as well as http://szhorvat.net/pelican/hh-connected-graphs.html 
+ *          for a proof. In the directed case it tends to generate weakly connected graphs, but this is not
  *          guaranteed.
  *          \cli IGRAPH_REALIZE_DEGSEQ_LARGEST
  *          The vertex with the largest remaining degree is selected first. The result
diff --git a/igraph/src/distances.c b/igraph/src/distances.c
--- a/igraph/src/distances.c
+++ b/igraph/src/distances.c
@@ -22,6 +22,7 @@
 
 */
 
+#include "igraph_paths.h"
 #include "igraph_datatype.h"
 #include "igraph_dqueue.h"
 #include "igraph_iterators.h"
@@ -30,11 +31,11 @@
 #include "igraph_interface.h"
 #include "igraph_adjlist.h"
 
-int igraph_i_eccentricity(const igraph_t *graph,
-                          igraph_vector_t *res,
-                          igraph_vs_t vids,
-                          igraph_neimode_t mode,
-                          const igraph_adjlist_t *adjlist) {
+static int igraph_i_eccentricity(const igraph_t *graph,
+                                 igraph_vector_t *res,
+                                 igraph_vs_t vids,
+                                 igraph_neimode_t mode,
+                                 const igraph_adjlist_t *adjlist) {
 
     int no_of_nodes = igraph_vcount(graph);
     igraph_dqueue_long_t q;
diff --git a/igraph/src/dotproduct.c b/igraph/src/dotproduct.c
--- a/igraph/src/dotproduct.c
+++ b/igraph/src/dotproduct.c
@@ -24,7 +24,7 @@
 #include "igraph_games.h"
 #include "igraph_random.h"
 #include "igraph_constructors.h"
-#include "igraph_lapack.h"
+#include "igraph_blas.h"
 
 /**
  * \function igraph_dot_product_game
@@ -80,7 +80,7 @@
                 continue;
             }
             igraph_vector_view(&v2, &MATRIX(*vecs, 0, j), nrow);
-            igraph_lapack_ddot(&v1, &v2, &prob);
+            igraph_blas_ddot(&v1, &v2, &prob);
             if (prob < 0 && ! warned_neg) {
                 warned_neg = 1;
                 IGRAPH_WARNING("Negative connection probability in "
diff --git a/igraph/src/drl_graph.cpp b/igraph/src/drl_graph.cpp
--- a/igraph/src/drl_graph.cpp
+++ b/igraph/src/drl_graph.cpp
@@ -32,13 +32,10 @@
  */
 // This file contains the member definitions of the master class
 
-#include <iostream>
-#include <fstream>
+
 #include <map>
 #include <vector>
-#include <cstdlib>
 #include <cmath>
-#include <cstring>
 
 using namespace std;
 
diff --git a/igraph/src/drl_graph_3d.cpp b/igraph/src/drl_graph_3d.cpp
--- a/igraph/src/drl_graph_3d.cpp
+++ b/igraph/src/drl_graph_3d.cpp
@@ -32,13 +32,9 @@
  */
 // This file contains the member definitions of the master class
 
-#include <iostream>
-#include <fstream>
 #include <map>
 #include <vector>
-#include <cstdlib>
 #include <cmath>
-#include <cstring>
 
 using namespace std;
 
diff --git a/igraph/src/drl_layout.cpp b/igraph/src/drl_layout.cpp
--- a/igraph/src/drl_layout.cpp
+++ b/igraph/src/drl_layout.cpp
@@ -45,12 +45,7 @@
 // 5/6/2005
 
 // C++ library routines
-#include <iostream>
-#include <fstream>
 #include <map>
-#include <set>
-#include <string>
-#include <deque>
 #include <vector>
 
 using namespace std;
@@ -70,6 +65,8 @@
 #include "igraph_random.h"
 #include "igraph_interface.h"
 
+#include "igraph_handle_exceptions.h"
+
 namespace drl {
 
 // int main(int argc, char **argv) {
@@ -460,17 +457,19 @@
                       const igraph_vector_t *weights,
                       const igraph_vector_bool_t *fixed) {
 
-    RNG_BEGIN();
+    IGRAPH_HANDLE_EXCEPTIONS(
+        RNG_BEGIN();
 
-    drl::graph neighbors(graph, options, weights);
-    neighbors.init_parms(options);
-    if (use_seed) {
-        IGRAPH_CHECK(igraph_matrix_resize(res, igraph_vcount(graph), 2));
-        neighbors.read_real(res, fixed);
-    }
-    neighbors.draw_graph(res);
+        drl::graph neighbors(graph, options, weights);
+        neighbors.init_parms(options);
+        if (use_seed) {
+            IGRAPH_CHECK(igraph_matrix_resize(res, igraph_vcount(graph), 2));
+            neighbors.read_real(res, fixed);
+        }
+        neighbors.draw_graph(res);
 
-    RNG_END();
+        RNG_END();
+    );
 
     return 0;
 }
diff --git a/igraph/src/drl_layout_3d.cpp b/igraph/src/drl_layout_3d.cpp
--- a/igraph/src/drl_layout_3d.cpp
+++ b/igraph/src/drl_layout_3d.cpp
@@ -45,12 +45,7 @@
 // 5/6/2005
 
 // C++ library routines
-#include <iostream>
-#include <fstream>
 #include <map>
-#include <set>
-#include <string>
-#include <deque>
 #include <vector>
 
 using namespace std;
@@ -70,6 +65,8 @@
 #include "igraph_random.h"
 #include "igraph_interface.h"
 
+#include "igraph_handle_exceptions.h"
+
 /**
  * \function igraph_layout_drl_3d
  * The DrL layout generator, 3d version.
@@ -106,18 +103,19 @@
                          igraph_layout_drl_options_t *options,
                          const igraph_vector_t *weights,
                          const igraph_vector_bool_t *fixed) {
-
-    RNG_BEGIN();
+    IGRAPH_HANDLE_EXCEPTIONS(
+        RNG_BEGIN();
 
-    drl3d::graph neighbors(graph, options, weights);
-    neighbors.init_parms(options);
-    if (use_seed) {
-        IGRAPH_CHECK(igraph_matrix_resize(res, igraph_vcount(graph), 3));
-        neighbors.read_real(res, fixed);
-    }
-    neighbors.draw_graph(res);
+        drl3d::graph neighbors(graph, options, weights);
+        neighbors.init_parms(options);
+        if (use_seed) {
+            IGRAPH_CHECK(igraph_matrix_resize(res, igraph_vcount(graph), 3));
+            neighbors.read_real(res, fixed);
+        }
+        neighbors.draw_graph(res);
 
-    RNG_END();
+        RNG_END();
+    );
 
     return 0;
 }
diff --git a/igraph/src/drl_parse.cpp b/igraph/src/drl_parse.cpp
--- a/igraph/src/drl_parse.cpp
+++ b/igraph/src/drl_parse.cpp
@@ -32,14 +32,6 @@
  */
 // This file contains the methods for the parse.h class
 
-#include <string>
-#include <iostream>
-#include <map>
-#include <cstdlib>
-#include <cstdio>
-
-using namespace std;
-
 #include "drl_layout.h"
 #include "drl_parse.h"
 
diff --git a/igraph/src/eigen.c b/igraph/src/eigen.c
--- a/igraph/src/eigen.c
+++ b/igraph/src/eigen.c
@@ -30,7 +30,7 @@
 #include <math.h>
 #include <float.h>
 
-int igraph_i_eigen_arpackfun_to_mat(igraph_arpack_function_t *fun,
+static int igraph_i_eigen_arpackfun_to_mat(igraph_arpack_function_t *fun,
                                     int n, void *extra,
                                     igraph_matrix_t *res) {
 
@@ -55,7 +55,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack_lm(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack_lm(const igraph_matrix_t *A,
         const igraph_eigen_which_t *which,
         igraph_vector_t *values,
         igraph_matrix_t *vectors) {
@@ -133,7 +133,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack_sm(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack_sm(const igraph_matrix_t *A,
         const igraph_eigen_which_t *which,
         igraph_vector_t *values,
         igraph_matrix_t *vectors) {
@@ -209,7 +209,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack_la(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack_la(const igraph_matrix_t *A,
         const igraph_eigen_which_t *which,
         igraph_vector_t *values,
         igraph_matrix_t *vectors) {
@@ -226,7 +226,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack_sa(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack_sa(const igraph_matrix_t *A,
         const igraph_eigen_which_t *which,
         igraph_vector_t *values,
         igraph_matrix_t *vectors) {
@@ -242,7 +242,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack_be(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack_be(const igraph_matrix_t *A,
         const igraph_eigen_which_t *which,
         igraph_vector_t *values,
         igraph_matrix_t *vectors) {
@@ -321,7 +321,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack_all(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack_all(const igraph_matrix_t *A,
         igraph_vector_t *values,
         igraph_matrix_t *vectors) {
 
@@ -334,7 +334,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack_iv(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack_iv(const igraph_matrix_t *A,
         const igraph_eigen_which_t *which,
         igraph_vector_t *values,
         igraph_matrix_t *vectors) {
@@ -349,7 +349,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack_sel(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack_sel(const igraph_matrix_t *A,
         const igraph_eigen_which_t *which,
         igraph_vector_t *values,
         igraph_matrix_t *vectors) {
@@ -363,7 +363,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_lapack(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_lapack(const igraph_matrix_t *A,
         const igraph_sparsemat_t *sA,
         igraph_arpack_function_t *fun,
         int n, void *extra,
@@ -444,7 +444,7 @@
     const igraph_sparsemat_t *sA;
 } igraph_i_eigen_matrix_sym_arpack_data_t;
 
-int igraph_i_eigen_matrix_sym_arpack_cb(igraph_real_t *to,
+static int igraph_i_eigen_matrix_sym_arpack_cb(igraph_real_t *to,
                                         const igraph_real_t *from,
                                         int n, void *extra) {
 
@@ -457,14 +457,14 @@
     } else { /* data->sA */
         igraph_vector_t vto, vfrom;
         igraph_vector_view(&vto, to, n);
-        igraph_vector_view(&vfrom, to, n);
+        igraph_vector_view(&vfrom, from, n);
         igraph_vector_null(&vto);
         igraph_sparsemat_gaxpy(data->sA, &vfrom, &vto);
     }
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_arpack_be(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_arpack_be(const igraph_matrix_t *A,
         const igraph_sparsemat_t *sA,
         igraph_arpack_function_t *fun,
         int n, void *extra,
@@ -535,7 +535,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_symmetric_arpack(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_symmetric_arpack(const igraph_matrix_t *A,
         const igraph_sparsemat_t *sA,
         igraph_arpack_function_t *fun,
         int n, void *extra,
@@ -637,7 +637,7 @@
    3 Larger real part
    4 Larger imaginary part */
 
-int igraph_i_eigen_matrix_lapack_cmp_lm(void *extra, const void *a,
+static int igraph_i_eigen_matrix_lapack_cmp_lm(void *extra, const void *a,
                                         const void *b) {
     igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra;
     int *aa = (int*) a, *bb = (int*) b;
@@ -682,7 +682,7 @@
    4 Smaller imaginary part
    This ensures that lm has exactly the opposite order to sm */
 
-int igraph_i_eigen_matrix_lapack_cmp_sm(void *extra, const void *a,
+static int igraph_i_eigen_matrix_lapack_cmp_sm(void *extra, const void *a,
                                         const void *b) {
     igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra;
     int *aa = (int*) a, *bb = (int*) b;
@@ -725,7 +725,7 @@
    2 Real eigenvalues come before complex ones
    3 Larger complex part */
 
-int igraph_i_eigen_matrix_lapack_cmp_lr(void *extra, const void *a,
+static int igraph_i_eigen_matrix_lapack_cmp_lr(void *extra, const void *a,
                                         const void *b) {
 
     igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra;
@@ -764,7 +764,7 @@
    This is opposite to LR
 */
 
-int igraph_i_eigen_matrix_lapack_cmp_sr(void *extra, const void *a,
+static int igraph_i_eigen_matrix_lapack_cmp_sr(void *extra, const void *a,
                                         const void *b) {
 
     igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra;
@@ -801,7 +801,7 @@
    2 Real eigenvalues before complex ones
    3 Larger real part */
 
-int igraph_i_eigen_matrix_lapack_cmp_li(void *extra, const void *a,
+static int igraph_i_eigen_matrix_lapack_cmp_li(void *extra, const void *a,
                                         const void *b) {
 
     igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra;
@@ -839,7 +839,7 @@
    3 Smaller real part
    Order is opposite to LI */
 
-int igraph_i_eigen_matrix_lapack_cmp_si(void *extra, const void *a,
+static int igraph_i_eigen_matrix_lapack_cmp_si(void *extra, const void *a,
                                         const void *b) {
 
     igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra;
@@ -888,7 +888,7 @@
         }                                   \
     } while (0)
 
-int igraph_i_eigen_matrix_lapack_reorder(const igraph_vector_t *real,
+static int igraph_i_eigen_matrix_lapack_reorder(const igraph_vector_t *real,
         const igraph_vector_t *imag,
         const igraph_matrix_t *compressed,
         const igraph_eigen_which_t *which,
@@ -1006,7 +1006,7 @@
     return 0;
 }
 
-int igraph_i_eigen_matrix_lapack_common(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_common(const igraph_matrix_t *A,
                                         const igraph_eigen_which_t *which,
                                         igraph_vector_complex_t *values,
                                         igraph_matrix_complex_t *vectors) {
@@ -1042,21 +1042,21 @@
 
 }
 
-int igraph_i_eigen_matrix_lapack_lm(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_lm(const igraph_matrix_t *A,
                                     const igraph_eigen_which_t *which,
                                     igraph_vector_complex_t *values,
                                     igraph_matrix_complex_t *vectors) {
     return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
 }
 
-int igraph_i_eigen_matrix_lapack_sm(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_sm(const igraph_matrix_t *A,
                                     const igraph_eigen_which_t *which,
                                     igraph_vector_complex_t *values,
                                     igraph_matrix_complex_t *vectors) {
     return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
 }
 
-int igraph_i_eigen_matrix_lapack_lr(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_lr(const igraph_matrix_t *A,
                                     const igraph_eigen_which_t *which,
                                     igraph_vector_complex_t *values,
                                     igraph_matrix_complex_t *vectors) {
@@ -1064,42 +1064,42 @@
 }
 
 
-int igraph_i_eigen_matrix_lapack_sr(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_sr(const igraph_matrix_t *A,
                                     const igraph_eigen_which_t *which,
                                     igraph_vector_complex_t *values,
                                     igraph_matrix_complex_t *vectors) {
     return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
 }
 
-int igraph_i_eigen_matrix_lapack_li(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_li(const igraph_matrix_t *A,
                                     const igraph_eigen_which_t *which,
                                     igraph_vector_complex_t *values,
                                     igraph_matrix_complex_t *vectors) {
     return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
 }
 
-int igraph_i_eigen_matrix_lapack_si(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_si(const igraph_matrix_t *A,
                                     const igraph_eigen_which_t *which,
                                     igraph_vector_complex_t *values,
                                     igraph_matrix_complex_t *vectors) {
     return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
 }
 
-int igraph_i_eigen_matrix_lapack_select(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_select(const igraph_matrix_t *A,
                                         const igraph_eigen_which_t *which,
                                         igraph_vector_complex_t *values,
                                         igraph_matrix_complex_t *vectors) {
     return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
 }
 
-int igraph_i_eigen_matrix_lapack_all(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack_all(const igraph_matrix_t *A,
                                      const igraph_eigen_which_t *which,
                                      igraph_vector_complex_t *values,
                                      igraph_matrix_complex_t *vectors) {
     return igraph_i_eigen_matrix_lapack_common(A, which, values, vectors);
 }
 
-int igraph_i_eigen_matrix_lapack(const igraph_matrix_t *A,
+static int igraph_i_eigen_matrix_lapack(const igraph_matrix_t *A,
                                  const igraph_sparsemat_t *sA,
                                  igraph_arpack_function_t *fun,
                                  int n, void *extra,
@@ -1172,7 +1172,7 @@
     return 0;
 }
 
-int igraph_i_eigen_checks(const igraph_matrix_t *A,
+static int igraph_i_eigen_checks(const igraph_matrix_t *A,
                           const igraph_sparsemat_t *sA,
                           igraph_arpack_function_t *fun, int n) {
 
@@ -1322,7 +1322,7 @@
     return 0;
 }
 
-int igraph_i_eigen_adjacency_arpack_sym_cb(igraph_real_t *to,
+static int igraph_i_eigen_adjacency_arpack_sym_cb(igraph_real_t *to,
         const igraph_real_t *from,
         int n, void *extra) {
     igraph_adjlist_t *adjlist = (igraph_adjlist_t *) extra;
@@ -1342,7 +1342,7 @@
     return 0;
 }
 
-int igraph_i_eigen_adjacency_arpack(const igraph_t *graph,
+static int igraph_i_eigen_adjacency_arpack(const igraph_t *graph,
                                     const igraph_eigen_which_t *which,
                                     igraph_arpack_options_t *options,
                                     igraph_arpack_storage_t* storage,
diff --git a/igraph/src/embedding.c b/igraph/src/embedding.c
--- a/igraph/src/embedding.c
+++ b/igraph/src/embedding.c
@@ -24,7 +24,6 @@
 #include "igraph_embedding.h"
 #include "igraph_interface.h"
 #include "igraph_adjlist.h"
-#include "igraph_random.h"
 #include "igraph_centrality.h"
 #include "igraph_blas.h"
 
@@ -40,7 +39,7 @@
 
 /* Adjacency matrix, unweighted, undirected.
    Eigendecomposition is used */
-int igraph_i_asembeddingu(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_asembeddingu(igraph_real_t *to, const igraph_real_t *from,
                           int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
     igraph_adjlist_t *outlist = data->outlist;
@@ -65,7 +64,7 @@
 
 /* Adjacency matrix, weighted, undirected.
    Eigendecomposition is used. */
-int igraph_i_asembeddinguw(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_asembeddinguw(igraph_real_t *to, const igraph_real_t *from,
                            int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
     igraph_inclist_t *outlist = data->eoutlist;
@@ -93,7 +92,7 @@
 }
 
 /* Adjacency matrix, unweighted, directed. SVD. */
-int igraph_i_asembedding(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_asembedding(igraph_real_t *to, const igraph_real_t *from,
                          int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
     igraph_adjlist_t *outlist = data->outlist;
@@ -131,7 +130,7 @@
 }
 
 /* Adjacency matrix, unweighted, directed. SVD, right eigenvectors */
-int igraph_i_asembedding_right(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_asembedding_right(igraph_real_t *to, const igraph_real_t *from,
                                int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
     igraph_adjlist_t *inlist = data->inlist;
@@ -155,7 +154,7 @@
 }
 
 /* Adjacency matrix, weighted, directed. SVD. */
-int igraph_i_asembeddingw(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_asembeddingw(igraph_real_t *to, const igraph_real_t *from,
                           int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
     igraph_inclist_t *outlist = data->eoutlist;
@@ -199,7 +198,7 @@
 }
 
 /* Adjacency matrix, weighted, directed. SVD, right eigenvectors. */
-int igraph_i_asembeddingw_right(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_asembeddingw_right(igraph_real_t *to, const igraph_real_t *from,
                                 int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
     igraph_inclist_t *inlist = data->einlist;
@@ -227,7 +226,7 @@
 }
 
 /* Laplacian D-A, unweighted, undirected. Eigendecomposition. */
-int igraph_i_lsembedding_da(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_lsembedding_da(igraph_real_t *to, const igraph_real_t *from,
                             int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
     igraph_adjlist_t *outlist = data->outlist;
@@ -251,7 +250,7 @@
 }
 
 /* Laplacian D-A, weighted, undirected. Eigendecomposition. */
-int igraph_i_lsembedding_daw(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_lsembedding_daw(igraph_real_t *to, const igraph_real_t *from,
                              int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
     igraph_inclist_t *outlist = data->eoutlist;
@@ -279,7 +278,7 @@
 }
 
 /* Laplacian DAD, unweighted, undirected. Eigendecomposition. */
-int igraph_i_lsembedding_dad(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_lsembedding_dad(igraph_real_t *to, const igraph_real_t *from,
                              int n, void *extra) {
 
     igraph_i_asembedding_data_t *data = extra;
@@ -313,7 +312,7 @@
     return 0;
 }
 
-int igraph_i_lsembedding_dadw(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_lsembedding_dadw(igraph_real_t *to, const igraph_real_t *from,
                               int n, void *extra) {
 
     igraph_i_asembedding_data_t *data = extra;
@@ -370,7 +369,7 @@
 }
 
 /* Laplacian I-DAD, unweighted, undirected. Eigendecomposition. */
-int igraph_i_lsembedding_idad(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_lsembedding_idad(igraph_real_t *to, const igraph_real_t *from,
                               int n, void *extra) {
 
     int i;
@@ -383,7 +382,7 @@
     return 0;
 }
 
-int igraph_i_lsembedding_idadw(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_lsembedding_idadw(igraph_real_t *to, const igraph_real_t *from,
                                int n, void *extra) {
     int i;
 
@@ -396,7 +395,7 @@
 }
 
 /* Laplacian OAP, unweighted, directed. SVD. */
-int igraph_i_lseembedding_oap(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_lseembedding_oap(igraph_real_t *to, const igraph_real_t *from,
                               int n, void *extra) {
 
     igraph_i_asembedding_data_t *data = extra;
@@ -454,7 +453,7 @@
 }
 
 /* Laplacian OAP, unweighted, directed. SVD, right eigenvectors. */
-int igraph_i_lseembedding_oap_right(igraph_real_t *to,
+static int igraph_i_lseembedding_oap_right(igraph_real_t *to,
                                     const igraph_real_t *from,
                                     int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
@@ -490,7 +489,7 @@
 }
 
 /* Laplacian OAP, weighted, directed. SVD. */
-int igraph_i_lseembedding_oapw(igraph_real_t *to, const igraph_real_t *from,
+static int igraph_i_lseembedding_oapw(igraph_real_t *to, const igraph_real_t *from,
                                int n, void *extra) {
 
     igraph_i_asembedding_data_t *data = extra;
@@ -554,7 +553,7 @@
 }
 
 /* Laplacian OAP, weighted, directed. SVD, right eigenvectors. */
-int igraph_i_lseembedding_oapw_right(igraph_real_t *to,
+static int igraph_i_lseembedding_oapw_right(igraph_real_t *to,
                                      const igraph_real_t *from,
                                      int n, void *extra) {
     igraph_i_asembedding_data_t *data = extra;
@@ -593,7 +592,7 @@
     return 0;
 }
 
-int igraph_i_spectral_embedding(const igraph_t *graph,
+static int igraph_i_spectral_embedding(const igraph_t *graph,
                                 igraph_integer_t no,
                                 const igraph_vector_t *weights,
                                 igraph_eigen_which_position_t which,
@@ -785,29 +784,29 @@
  * Adjacency spectral embedding
  *
  * Spectral decomposition of the adjacency matrices of graphs.
- * This function computes a \code{no}-dimensional Euclidean
+ * This function computes an <code>n</code>-dimensional Euclidean
  * representation of the graph based on its adjacency
  * matrix, A. This representation is computed via the singular value
- * decomposition of the adjacency matrix, A=UDV^T. In the case,
+ * decomposition of the adjacency matrix, A=U D V^T. In the case,
  * where the graph is a random dot product graph generated using latent
- * position vectors in R^no for each vertex, the embedding will
+ * position vectors in R^n for each vertex, the embedding will
  * provide an estimate of these latent vectors.
  *
  * </para><para>
- * For undirected graphs the latent positions are calculated as
- * X=U^no D^(1/2) where U^no equals to the first no columns of U, and
+ * For undirected graphs, the latent positions are calculated as
+ * X = U^n D^(1/2) where U^n equals to the first no columns of U, and
  * D^(1/2) is a diagonal matrix containing the square root of the selected
  * singular values on the diagonal.
  *
  * </para><para>
- * For directed graphs the embedding is defined as the pair
- * X=U^no D^(1/2), Y=V^no D^(1/2). (For undirected graphs U=V,
- * so it is enough to keep one of them.)
+ * For directed graphs, the embedding is defined as the pair
+ * X = U^n D^(1/2), Y = V^n D^(1/2).
+ * (For undirected graphs U=V, so it is sufficient to keep one of them.)
  *
  * \param graph The input graph, can be directed or undirected.
- * \param no An integer scalar. This value is the embedding dimension of
+ * \param n An integer scalar. This value is the embedding dimension of
  *        the spectral embedding. Should be smaller than the number of
- *        vertices. The largest no-dimensional non-zero
+ *        vertices. The largest n-dimensional non-zero
  *        singular values are used for the spectral embedding.
  * \param weights Optional edge weights. Supply a null pointer for
  *        unweighted graphs.
@@ -824,7 +823,7 @@
  *        For directed graphs, <code>IGRAPH_EIGEN_LM</code> and
  *        <code>IGRAPH_EIGEN_LA</code> are the same because singular
  *        values are used for the ordering instead of eigenvalues.
- * \param scaled Whether to return X and Y (if scaled is non-zero), or
+ * \param scaled Whether to return X and Y (if \c scaled is true), or
  *        U and V.
  * \param X Initialized matrix, the estimated latent positions are
  *        stored here.
@@ -847,7 +846,7 @@
  */
 
 int igraph_adjacency_spectral_embedding(const igraph_t *graph,
-                                        igraph_integer_t no,
+                                        igraph_integer_t n,
                                         const igraph_vector_t *weights,
                                         igraph_eigen_which_position_t which,
                                         igraph_bool_t scaled,
@@ -869,14 +868,14 @@
         callback_right = 0;
     }
 
-    return igraph_i_spectral_embedding(graph, no, weights, which, scaled,
+    return igraph_i_spectral_embedding(graph, n, weights, which, scaled,
                                        X, Y, D, cvec, /* deg2=*/ 0,
                                        options, callback, callback_right,
                                        /*symmetric=*/ !directed,
                                        /*eigen=*/ !directed, /*zapsmall=*/ 1);
 }
 
-int igraph_i_lse_und(const igraph_t *graph,
+static int igraph_i_lse_und(const igraph_t *graph,
                      igraph_integer_t no,
                      const igraph_vector_t *weights,
                      igraph_eigen_which_position_t which,
@@ -937,7 +936,7 @@
     return 0;
 }
 
-int igraph_i_lse_dir(const igraph_t *graph,
+static int igraph_i_lse_dir(const igraph_t *graph,
                      igraph_integer_t no,
                      const igraph_vector_t *weights,
                      igraph_eigen_which_position_t which,
@@ -994,7 +993,7 @@
  * \ref igraph_adjacency_spectral_embedding, but works on the Laplacian
  * of the graph, instead of the adjacency matrix.
  * \param graph The input graph.
- * \param no The number of eigenvectors (or singular vectors if the graph
+ * \param n The number of eigenvectors (or singular vectors if the graph
  *        is directed) to use for the embedding.
  * \param weights Optional edge weights. Supply a null pointer for
  *        unweighted graphs.
@@ -1025,7 +1024,7 @@
  *          means I - Di A Di, where I
  *          is the identity matrix.
  *        \endclist
- * \param scaled Whether to return X and Y (if scaled is non-zero), or
+ * \param scaled Whether to return X and Y (if \c scaled is true), or
  *        U and V.
  * \param X Initialized matrix, the estimated latent positions are
  *        stored here.
@@ -1047,7 +1046,7 @@
  */
 
 int igraph_laplacian_spectral_embedding(const igraph_t *graph,
-                                        igraph_integer_t no,
+                                        igraph_integer_t n,
                                         const igraph_vector_t *weights,
                                         igraph_eigen_which_position_t which,
                                         igraph_neimode_t degmode,
@@ -1059,10 +1058,10 @@
                                         igraph_arpack_options_t *options) {
 
     if (igraph_is_directed(graph)) {
-        return igraph_i_lse_dir(graph, no, weights, which, degmode, type, scaled,
+        return igraph_i_lse_dir(graph, n, weights, which, degmode, type, scaled,
                                 X, Y, D, options);
     } else {
-        return igraph_i_lse_und(graph, no, weights, which, degmode, type, scaled,
+        return igraph_i_lse_und(graph, n, weights, which, degmode, type, scaled,
                                 X, Y, D, options);
     }
 }
@@ -1090,7 +1089,7 @@
  * </para><para>
  * This function can also be used for the general separation problem,
  * where we assume that the left and the right of the vector are coming
- * from two Normal distributions, with different means, and we want
+ * from two normal distributions, with different means, and we want
  * to know their border.
  *
  * \param sv A numeric vector, the ordered singular values.
diff --git a/igraph/src/error.c b/igraph/src/error.c
--- a/igraph/src/error.c
+++ b/igraph/src/error.c
@@ -4,14 +4,14 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include "error.h"
+#include "platform.h"
 
 static char *plfit_i_error_strings[] = {
     "No error",
@@ -69,6 +70,6 @@
 }
 #endif
 
-void plfit_error_handler_ignore(const char *reason, const char *file, int line,
-        int plfit_errno) {
+void plfit_error_handler_ignore(const char* reason, const char* file, int line,
+		int plfit_errno) {
 }
diff --git a/igraph/src/fast_community.c b/igraph/src/fast_community.c
--- a/igraph/src/fast_community.c
+++ b/igraph/src/fast_community.c
@@ -109,8 +109,8 @@
 /* Scans the community neighborhood list for the new maximal dq value.
  * Returns 1 if the maximum is different from the previous one,
  * 0 otherwise. */
-int igraph_i_fastgreedy_community_rescan_max(
-    igraph_i_fastgreedy_community* comm) {
+static int igraph_i_fastgreedy_community_rescan_max(
+        igraph_i_fastgreedy_community* comm) {
     long int i, n;
     igraph_i_fastgreedy_commpair *p, *best;
     igraph_real_t bestdq, currdq;
@@ -141,24 +141,24 @@
 }
 
 /* Destroys the global community list object */
-void igraph_i_fastgreedy_community_list_destroy(
-    igraph_i_fastgreedy_community_list* list) {
+static void igraph_i_fastgreedy_community_list_destroy(
+        igraph_i_fastgreedy_community_list* list) {
     long int i;
     for (i = 0; i < list->n; i++) {
         igraph_vector_ptr_destroy(&list->e[i].neis);
     }
-    free(list->e);
+    igraph_Free(list->e);
     if (list->heapindex != 0) {
-        free(list->heapindex);
+        igraph_Free(list->heapindex);
     }
     if (list->heap != 0) {
-        free(list->heap);
+        igraph_Free(list->heap);
     }
 }
 
 /* Community list heap maintenance: sift down */
-void igraph_i_fastgreedy_community_list_sift_down(
-    igraph_i_fastgreedy_community_list* list, long int idx) {
+static void igraph_i_fastgreedy_community_list_sift_down(
+        igraph_i_fastgreedy_community_list* list, long int idx) {
     long int root, child, c1, c2;
     igraph_i_fastgreedy_community* dummy;
     igraph_integer_t dummy2;
@@ -192,8 +192,8 @@
 }
 
 /* Community list heap maintenance: sift up */
-void igraph_i_fastgreedy_community_list_sift_up(
-    igraph_i_fastgreedy_community_list* list, long int idx) {
+static void igraph_i_fastgreedy_community_list_sift_up(
+        igraph_i_fastgreedy_community_list* list, long int idx) {
     long int root, parent, c1, c2;
     igraph_i_fastgreedy_community* dummy;
     igraph_integer_t dummy2;
@@ -223,8 +223,8 @@
 }
 
 /* Builds the community heap for the first time */
-void igraph_i_fastgreedy_community_list_build_heap(
-    igraph_i_fastgreedy_community_list* list) {
+static void igraph_i_fastgreedy_community_list_build_heap(
+        igraph_i_fastgreedy_community_list* list) {
     long int i;
     for (i = list->no_of_communities / 2 - 1; i >= 0; i--) {
         igraph_i_fastgreedy_community_list_sift_down(list, i);
@@ -236,8 +236,8 @@
 #define igraph_i_fastgreedy_community_list_find_in_heap(list, idx) (list)->heapindex[idx]
 
 /* Dumps the heap - for debugging purposes */
-void igraph_i_fastgreedy_community_list_dump_heap(
-    igraph_i_fastgreedy_community_list* list) {
+static void igraph_i_fastgreedy_community_list_dump_heap(
+        igraph_i_fastgreedy_community_list* list) {
     long int i;
     debug("Heap:\n");
     for (i = 0; i < list->no_of_communities; i++) {
@@ -258,8 +258,8 @@
 
 /* Checks if the community heap satisfies the heap property.
  * Only useful for debugging. */
-void igraph_i_fastgreedy_community_list_check_heap(
-    igraph_i_fastgreedy_community_list* list) {
+static void igraph_i_fastgreedy_community_list_check_heap(
+        igraph_i_fastgreedy_community_list* list) {
     long int i;
     for (i = 0; i < list->no_of_communities / 2; i++) {
         if ((2 * i + 1 < list->no_of_communities && *list->heap[i]->maxdq->dq < *list->heap[2 * i + 1]->maxdq->dq) ||
@@ -272,8 +272,8 @@
 }
 
 /* Removes a given element from the heap */
-void igraph_i_fastgreedy_community_list_remove(
-    igraph_i_fastgreedy_community_list* list, long int idx) {
+static void igraph_i_fastgreedy_community_list_remove(
+        igraph_i_fastgreedy_community_list* list, long int idx) {
     igraph_real_t old;
     long int commidx;
 
@@ -298,8 +298,8 @@
 
 /* Removes a given element from the heap when there are no more neighbors
  * for it (comm->maxdq is NULL) */
-void igraph_i_fastgreedy_community_list_remove2(
-    igraph_i_fastgreedy_community_list* list, long int idx, long int comm) {
+static void igraph_i_fastgreedy_community_list_remove2(
+        igraph_i_fastgreedy_community_list* list, long int idx, long int comm) {
     long int i;
 
     if (idx == list->no_of_communities - 1) {
@@ -327,8 +327,8 @@
 
 /* Removes the pair belonging to community k from the neighborhood list
  * of community c (that is, clist[c]) and recalculates maxdq */
-void igraph_i_fastgreedy_community_remove_nei(
-    igraph_i_fastgreedy_community_list* list, long int c, long int k) {
+static void igraph_i_fastgreedy_community_remove_nei(
+        igraph_i_fastgreedy_community_list* list, long int c, long int k) {
     long int i, n;
     igraph_bool_t rescan = 0;
     igraph_i_fastgreedy_commpair *p;
@@ -371,7 +371,7 @@
 
 /* Auxiliary function to sort a community pair list with respect to the
  * `second` field */
-int igraph_i_fastgreedy_commpair_cmp(const void* p1, const void* p2) {
+static int igraph_i_fastgreedy_commpair_cmp(const void* p1, const void* p2) {
     igraph_i_fastgreedy_commpair *cp1, *cp2;
     cp1 = *(igraph_i_fastgreedy_commpair**)p1;
     cp2 = *(igraph_i_fastgreedy_commpair**)p2;
@@ -381,9 +381,9 @@
 /* Sorts the neighbor list of the community with the given index, optionally
  * optimizing the process if we know that the list is nearly sorted and only
  * a given pair is in the wrong place. */
-void igraph_i_fastgreedy_community_sort_neighbors_of(
-    igraph_i_fastgreedy_community_list* list, long int index,
-    igraph_i_fastgreedy_commpair* changed_pair) {
+static void igraph_i_fastgreedy_community_sort_neighbors_of(
+        igraph_i_fastgreedy_community_list* list, long int index,
+        igraph_i_fastgreedy_commpair* changed_pair) {
     igraph_vector_ptr_t* vec;
     long int i, n;
     igraph_bool_t can_skip_sort = 0;
@@ -453,9 +453,9 @@
  * of the community list clist to newdq and restores the heap property
  * in community c if necessary. Returns 1 if the maximum in the row had
  * to be updated, zero otherwise */
-int igraph_i_fastgreedy_community_update_dq(
-    igraph_i_fastgreedy_community_list* list,
-    igraph_i_fastgreedy_commpair* p, igraph_real_t newdq) {
+static int igraph_i_fastgreedy_community_update_dq(
+        igraph_i_fastgreedy_community_list* list,
+        igraph_i_fastgreedy_commpair* p, igraph_real_t newdq) {
     long int i, j, to, from;
     igraph_real_t olddq;
     igraph_i_fastgreedy_community *comm_to, *comm_from;
@@ -698,12 +698,12 @@
     if (communities.e == 0) {
         IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, communities.e);
+    IGRAPH_FINALLY(igraph_free, communities.e);
     communities.heap = (igraph_i_fastgreedy_community**)calloc((size_t) no_of_nodes, sizeof(igraph_i_fastgreedy_community*));
     if (communities.heap == 0) {
         IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, communities.heap);
+    IGRAPH_FINALLY(igraph_free, communities.heap);
     communities.heapindex = (igraph_integer_t*)calloc((size_t)no_of_nodes, sizeof(igraph_integer_t));
     if (communities.heapindex == 0) {
         IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
@@ -722,7 +722,7 @@
     if (dq == 0) {
         IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, dq);
+    IGRAPH_FINALLY(igraph_free, dq);
     debug("Creating community pair list\n");
     IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
     IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
@@ -730,7 +730,7 @@
     if (pairs == 0) {
         IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, pairs);
+    IGRAPH_FINALLY(igraph_free, pairs);
     loop_weight_sum = 0;
     for (i = 0, j = 0; !IGRAPH_EIT_END(edgeit); i += 2, j++, IGRAPH_EIT_NEXT(edgeit)) {
         long int eidx = IGRAPH_EIT_GET(edgeit);
@@ -1022,12 +1022,12 @@
         if (ivec == 0) {
             IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
         }
-        IGRAPH_FINALLY(free, ivec);
+        IGRAPH_FINALLY(igraph_free, ivec);
         for (i = 0; i < no_of_joins; i++) {
             ivec[i] = i + 1;
         }
         igraph_matrix_permdelete_rows(merges, ivec, total_joins - no_of_joins);
-        free(ivec);
+        igraph_Free(ivec);
         IGRAPH_FINALLY_CLEAN(1);
     }
     IGRAPH_PROGRESS("fast greedy community detection", 100.0, 0);
@@ -1038,8 +1038,8 @@
     }
 
     debug("Freeing memory\n");
-    free(pairs);
-    free(dq);
+    igraph_Free(pairs);
+    igraph_Free(dq);
     igraph_i_fastgreedy_community_list_destroy(&communities);
     igraph_vector_destroy(&a);
     IGRAPH_FINALLY_CLEAN(4);
diff --git a/igraph/src/feedback_arc_set.c b/igraph/src/feedback_arc_set.c
--- a/igraph/src/feedback_arc_set.c
+++ b/igraph/src/feedback_arc_set.c
@@ -475,7 +475,7 @@
         if (vptr == 0) {
             IGRAPH_ERROR("cannot calculate feedback arc set using IP", IGRAPH_ENOMEM);
         }
-        IGRAPH_FINALLY(free, vptr);
+        IGRAPH_FINALLY(igraph_free, vptr);
         IGRAPH_CHECK(igraph_vector_init(vptr, 0));
         IGRAPH_FINALLY_CLEAN(1);
         VECTOR(vertices_by_components)[i] = vptr;
@@ -487,7 +487,7 @@
         if (vptr == 0) {
             IGRAPH_ERROR("cannot calculate feedback arc set using IP", IGRAPH_ENOMEM);
         }
-        IGRAPH_FINALLY(free, vptr);
+        IGRAPH_FINALLY(igraph_free, vptr);
         IGRAPH_CHECK(igraph_vector_init(vptr, 0));
         IGRAPH_FINALLY_CLEAN(1);
         VECTOR(edges_by_components)[i] = vptr;
diff --git a/igraph/src/flow.c b/igraph/src/flow.c
--- a/igraph/src/flow.c
+++ b/igraph/src/flow.c
@@ -33,15 +33,12 @@
 #include "igraph_structural.h"
 #include "igraph_components.h"
 #include "igraph_types_internal.h"
-#include "config.h"
 #include "igraph_math.h"
 #include "igraph_dqueue.h"
-#include "igraph_visitor.h"
 #include "igraph_interrupt_internal.h"
 #include "igraph_topology.h"
+#include "config.h"
 
-#include <limits.h>
-#include <stdio.h>
 
 /*
  * Some general remarks about the functions in this file.
@@ -156,16 +153,16 @@
  * undirected edge.
  */
 
-int igraph_i_maxflow_undirected(const igraph_t *graph,
-                                igraph_real_t *value,
-                                igraph_vector_t *flow,
-                                igraph_vector_t *cut,
-                                igraph_vector_t *partition,
-                                igraph_vector_t *partition2,
-                                igraph_integer_t source,
-                                igraph_integer_t target,
-                                const igraph_vector_t *capacity,
-                                igraph_maxflow_stats_t *stats) {
+static int igraph_i_maxflow_undirected(const igraph_t *graph,
+                                       igraph_real_t *value,
+                                       igraph_vector_t *flow,
+                                       igraph_vector_t *cut,
+                                       igraph_vector_t *partition,
+                                       igraph_vector_t *partition2,
+                                       igraph_integer_t source,
+                                       igraph_integer_t target,
+                                       const igraph_vector_t *capacity,
+                                       igraph_maxflow_stats_t *stats) {
     igraph_integer_t no_of_edges = (igraph_integer_t) igraph_ecount(graph);
     igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph);
     igraph_vector_t edges;
@@ -253,10 +250,10 @@
                                         &first, &current, &to, &excess,       \
                                         &rescap, &rev))
 
-void igraph_i_mf_gap(long int b, igraph_maxflow_stats_t *stats,
-                     igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets,
-                     long int no_of_nodes,
-                     igraph_vector_long_t *distance) {
+static void igraph_i_mf_gap(long int b, igraph_maxflow_stats_t *stats,
+                            igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets,
+                            long int no_of_nodes,
+                            igraph_vector_long_t *distance) {
 
     long int bo;
     (stats->nogap)++;
@@ -269,12 +266,12 @@
     }
 }
 
-void igraph_i_mf_relabel(long int v, long int no_of_nodes,
-                         igraph_vector_long_t *distance,
-                         igraph_vector_long_t *first,
-                         igraph_vector_t *rescap, igraph_vector_long_t *to,
-                         igraph_vector_long_t *current,
-                         igraph_maxflow_stats_t *stats, int *nrelabelsince) {
+static void igraph_i_mf_relabel(long int v, long int no_of_nodes,
+                                igraph_vector_long_t *distance,
+                                igraph_vector_long_t *first,
+                                igraph_vector_t *rescap, igraph_vector_long_t *to,
+                                igraph_vector_long_t *current,
+                                igraph_maxflow_stats_t *stats, int *nrelabelsince) {
 
     long int min = no_of_nodes;
     long int k, l, min_edge = 0;
@@ -293,14 +290,14 @@
     }
 }
 
-void igraph_i_mf_push(long int v, long int e, long int n,
-                      igraph_vector_long_t *current,
-                      igraph_vector_t *rescap, igraph_vector_t *excess,
-                      long int target, long int source,
-                      igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets,
-                      igraph_vector_long_t *distance,
-                      igraph_vector_long_t *rev, igraph_maxflow_stats_t *stats,
-                      int *npushsince) {
+static void igraph_i_mf_push(long int v, long int e, long int n,
+                             igraph_vector_long_t *current,
+                             igraph_vector_t *rescap, igraph_vector_t *excess,
+                             long int target, long int source,
+                             igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets,
+                             igraph_vector_long_t *distance,
+                             igraph_vector_long_t *rev, igraph_maxflow_stats_t *stats,
+                             int *npushsince) {
     igraph_real_t delta =
         RESCAP(e) < EXCESS(v) ? RESCAP(e) : EXCESS(v);
     (stats->nopush)++; (*npushsince)++;
@@ -314,19 +311,19 @@
     EXCESS(v) -= delta;
 }
 
-void igraph_i_mf_discharge(long int v,
-                           igraph_vector_long_t *current,
-                           igraph_vector_long_t *first,
-                           igraph_vector_t *rescap,
-                           igraph_vector_long_t *to,
-                           igraph_vector_long_t *distance,
-                           igraph_vector_t *excess,
-                           long int no_of_nodes, long int source,
-                           long int target, igraph_buckets_t *buckets,
-                           igraph_dbuckets_t *ibuckets,
-                           igraph_vector_long_t *rev,
-                           igraph_maxflow_stats_t *stats,
-                           int *npushsince, int *nrelabelsince) {
+static void igraph_i_mf_discharge(long int v,
+                                  igraph_vector_long_t *current,
+                                  igraph_vector_long_t *first,
+                                  igraph_vector_t *rescap,
+                                  igraph_vector_long_t *to,
+                                  igraph_vector_long_t *distance,
+                                  igraph_vector_t *excess,
+                                  long int no_of_nodes, long int source,
+                                  long int target, igraph_buckets_t *buckets,
+                                  igraph_dbuckets_t *ibuckets,
+                                  igraph_vector_long_t *rev,
+                                  igraph_maxflow_stats_t *stats,
+                                  int *npushsince, int *nrelabelsince) {
     do {
         long int i;
         long int start = (long int) CURRENT(v);
@@ -360,14 +357,14 @@
     } while (1);
 }
 
-void igraph_i_mf_bfs(igraph_dqueue_long_t *bfsq,
-                     long int source, long int target,
-                     long int no_of_nodes, igraph_buckets_t *buckets,
-                     igraph_dbuckets_t *ibuckets,
-                     igraph_vector_long_t *distance,
-                     igraph_vector_long_t *first, igraph_vector_long_t *current,
-                     igraph_vector_long_t *to, igraph_vector_t *excess,
-                     igraph_vector_t *rescap, igraph_vector_long_t *rev) {
+static void igraph_i_mf_bfs(igraph_dqueue_long_t *bfsq,
+                            long int source, long int target,
+                            long int no_of_nodes, igraph_buckets_t *buckets,
+                            igraph_dbuckets_t *ibuckets,
+                            igraph_vector_long_t *distance,
+                            igraph_vector_long_t *first, igraph_vector_long_t *current,
+                            igraph_vector_long_t *to, igraph_vector_t *excess,
+                            igraph_vector_t *rescap, igraph_vector_long_t *rev) {
 
     long int k, l;
 
@@ -414,8 +411,8 @@
  * assigning positive real numbers to the edges and satisfying two
  * requirements: (1) the flow value is less than the capacity of the
  * edge and (2) at each vertex except the source and the target, the
- * incoming flow (ie. the sum of the flow on the incoming edges) is
- * the same as the outgoing flow (ie. the sum of the flow on the
+ * incoming flow (i.e. the sum of the flow on the incoming edges) is
+ * the same as the outgoing flow (i.e. the sum of the flow on the
  * outgoing edges). The value of the flow is the incoming flow at the
  * target vertex. The maximum flow is the flow with the maximum
  * value.
@@ -745,7 +742,7 @@
         IGRAPH_CHECK(igraph_vector_int_init(&added, no_of_nodes));
         IGRAPH_FINALLY(igraph_vector_int_destroy, &added);
         IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
-        IGRAPH_FINALLY(igraph_dqueue_destroy, &added);
+        IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
 
         igraph_dqueue_push(&Q, source);
         igraph_dqueue_push(&Q, 0);
@@ -1031,8 +1028,8 @@
  * assigning positive real numbers to the edges and satisfying two
  * requirements: (1) the flow value is less than the capacity of the
  * edge and (2) at each vertex except the source and the target, the
- * incoming flow (ie. the sum of the flow on the incoming edges) is
- * the same as the outgoing flow (ie. the sum of the flow on the
+ * incoming flow (i.e. the sum of the flow on the incoming edges) is
+ * the same as the outgoing flow (i.e. the sum of the flow on the
  * outgoing edges). The value of the flow is the incoming flow at the
  * target vertex. The maximum flow is the flow with the maximum
  * value. </para>
@@ -1212,12 +1209,12 @@
  * It can also calculate the cut itself, not just the cut value.
  */
 
-int igraph_i_mincut_undirected(const igraph_t *graph,
-                               igraph_real_t *res,
-                               igraph_vector_t *partition,
-                               igraph_vector_t *partition2,
-                               igraph_vector_t *cut,
-                               const igraph_vector_t *capacity) {
+static int igraph_i_mincut_undirected(const igraph_t *graph,
+                                      igraph_real_t *res,
+                                      igraph_vector_t *partition,
+                                      igraph_vector_t *partition2,
+                                      igraph_vector_t *cut,
+                                      const igraph_vector_t *capacity) {
 
     igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph);
     igraph_integer_t no_of_edges = (igraph_integer_t) igraph_ecount(graph);
@@ -1479,12 +1476,12 @@
     return 0;
 }
 
-int igraph_i_mincut_directed(const igraph_t *graph,
-                             igraph_real_t *value,
-                             igraph_vector_t *partition,
-                             igraph_vector_t *partition2,
-                             igraph_vector_t *cut,
-                             const igraph_vector_t *capacity) {
+static int igraph_i_mincut_directed(const igraph_t *graph,
+                                    igraph_real_t *value,
+                                    igraph_vector_t *partition,
+                                    igraph_vector_t *partition2,
+                                    igraph_vector_t *cut,
+                                    const igraph_vector_t *capacity) {
     long int i;
     long int no_of_nodes = igraph_vcount(graph);
     igraph_real_t flow;
@@ -1665,9 +1662,9 @@
 }
 
 
-int igraph_i_mincut_value_undirected(const igraph_t *graph,
-                                     igraph_real_t *res,
-                                     const igraph_vector_t *capacity) {
+static int igraph_i_mincut_value_undirected(const igraph_t *graph,
+                                            igraph_real_t *res,
+                                            const igraph_vector_t *capacity) {
     return igraph_i_mincut_undirected(graph, res, 0, 0, 0, capacity);
 }
 
@@ -1747,11 +1744,11 @@
     return 0;
 }
 
-int igraph_i_st_vertex_connectivity_directed(const igraph_t *graph,
-        igraph_integer_t *res,
-        igraph_integer_t source,
-        igraph_integer_t target,
-        igraph_vconn_nei_t neighbors) {
+static int igraph_i_st_vertex_connectivity_directed(const igraph_t *graph,
+                                                    igraph_integer_t *res,
+                                                    igraph_integer_t source,
+                                                    igraph_integer_t target,
+                                                    igraph_vconn_nei_t neighbors) {
 
     igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph);
     igraph_integer_t no_of_edges = (igraph_integer_t) igraph_ecount(graph);
@@ -1835,11 +1832,11 @@
     return 0;
 }
 
-int igraph_i_st_vertex_connectivity_undirected(const igraph_t *graph,
-        igraph_integer_t *res,
-        igraph_integer_t source,
-        igraph_integer_t target,
-        igraph_vconn_nei_t neighbors) {
+static int igraph_i_st_vertex_connectivity_undirected(const igraph_t *graph,
+                                                      igraph_integer_t *res,
+                                                      igraph_integer_t source,
+                                                      igraph_integer_t target,
+                                                      igraph_vconn_nei_t neighbors) {
 
     igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph);
     igraph_t newgraph;
@@ -1902,7 +1899,7 @@
  * target. Directed paths are considered in directed graphs.</para>
  *
  * <para>The vertex connectivity of a pair is the same as the number
- * of different (ie. node-independent) paths from source to
+ * of different (i.e. node-independent) paths from source to
  * target.</para>
  *
  * <para>The current implementation uses maximum flow calculations to
@@ -1953,8 +1950,8 @@
     return 0;
 }
 
-int igraph_i_vertex_connectivity_directed(const igraph_t *graph,
-        igraph_integer_t *res) {
+static int igraph_i_vertex_connectivity_directed(const igraph_t *graph,
+                                                 igraph_integer_t *res) {
 
     igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph);
     long int i, j;
@@ -1991,8 +1988,8 @@
     return 0;
 }
 
-int igraph_i_vertex_connectivity_undirected(const igraph_t *graph,
-        igraph_integer_t *res) {
+static int igraph_i_vertex_connectivity_undirected(const igraph_t *graph,
+                                                   igraph_integer_t *res) {
     igraph_t newgraph;
 
     IGRAPH_CHECK(igraph_copy(&newgraph, graph));
@@ -2008,9 +2005,9 @@
 }
 
 /* Use that vertex.connectivity(G) <= edge.connectivity(G) <= min(degree(G)) */
-int igraph_i_connectivity_checks(const igraph_t *graph,
-                                 igraph_integer_t *res,
-                                 igraph_bool_t *found) {
+static int igraph_i_connectivity_checks(const igraph_t *graph,
+                                        igraph_integer_t *res,
+                                        igraph_bool_t *found) {
     igraph_bool_t conn;
     *found = 0;
 
@@ -2529,4 +2526,3 @@
 
     return IGRAPH_SUCCESS;
 }
-
diff --git a/igraph/src/foreign-dl-lexer.c b/igraph/src/foreign-dl-lexer.c
--- a/igraph/src/foreign-dl-lexer.c
+++ b/igraph/src/foreign-dl-lexer.c
@@ -590,16 +590,16 @@
 #include "foreign-dl-parser.h"
 #define YY_EXTRA_TYPE igraph_i_dl_parsedata_t*
 #define YY_USER_ACTION yylloc->first_line = yylineno;
-/* We assume that 'file' is 'stderr' here. */
 #ifdef USING_R
 #define fprintf(file, msg, ...) (1)
-#endif
+#define YY_FATAL_ERROR(msg)                                     \
+  igraph_error("Fatal error in DL parser: " # msg, __FILE__,    \
+               __LINE__, IGRAPH_PARSEERROR);
 #ifdef stdout 
 #  undef stdout
 #endif
 #define stdout 0
-#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
-				__LINE__, IGRAPH_PARSEERROR);
+#endif
 #define YY_NO_INPUT 1
 
 #line 606 "foreign-dl-lexer.c"
diff --git a/igraph/src/foreign-gml-lexer.c b/igraph/src/foreign-gml-lexer.c
--- a/igraph/src/foreign-gml-lexer.c
+++ b/igraph/src/foreign-gml-lexer.c
@@ -499,16 +499,16 @@
 #include "foreign-gml-parser.h"
 #define YY_EXTRA_TYPE igraph_i_gml_parsedata_t*
 #define YY_USER_ACTION yylloc->first_line = yylineno;
-/* We assume that 'file' is 'stderr' here. */
 #ifdef USING_R
 #define fprintf(file, msg, ...) (1)
-#endif
+#define YY_FATAL_ERROR(msg)                                      \
+  igraph_error("Fatal error in GML parser: " # msg, __FILE__,    \
+               __LINE__, IGRAPH_PARSEERROR);
 #ifdef stdout 
 #  undef stdout
 #endif
 #define stdout 0
-#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
-				__LINE__, IGRAPH_PARSEERROR);
+#endif
 #define YY_NO_INPUT 1
 #line 514 "foreign-gml-lexer.c"
 
diff --git a/igraph/src/foreign-graphml.c b/igraph/src/foreign-graphml.c
--- a/igraph/src/foreign-graphml.c
+++ b/igraph/src/foreign-graphml.c
@@ -133,8 +133,8 @@
                     "attribute specifications", file, line, 0, target);
 }
 
-igraph_real_t igraph_i_graphml_parse_numeric(const char* char_data,
-        igraph_real_t default_value) {
+static igraph_real_t igraph_i_graphml_parse_numeric(const char* char_data,
+                                                    igraph_real_t default_value) {
     double result;
 
     if (char_data == 0) {
@@ -148,8 +148,8 @@
     return result;
 }
 
-igraph_bool_t igraph_i_graphml_parse_boolean(const char* char_data,
-        igraph_bool_t default_value) {
+static igraph_bool_t igraph_i_graphml_parse_boolean(const char* char_data,
+                                                    igraph_bool_t default_value) {
     int value;
     if (char_data == 0) {
         return default_value;
@@ -172,7 +172,7 @@
     return value != 0;
 }
 
-void igraph_i_graphml_attribute_record_destroy(igraph_i_graphml_attribute_record_t* rec) {
+static void igraph_i_graphml_attribute_record_destroy(igraph_i_graphml_attribute_record_t* rec) {
     if (rec->record.type == IGRAPH_ATTRIBUTE_NUMERIC) {
         if (rec->record.value != 0) {
             igraph_vector_destroy((igraph_vector_t*)rec->record.value);
@@ -200,7 +200,7 @@
     }
 }
 
-void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {
+static void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {
     if (state->destroyed) {
         return;
     }
@@ -231,7 +231,7 @@
     IGRAPH_FINALLY_CLEAN(1);
 }
 
-void igraph_i_graphml_sax_handler_error(void *state0, const char* msg, ...) {
+static void igraph_i_graphml_sax_handler_error(void *state0, const char* msg, ...) {
     struct igraph_i_graphml_parser_state *state =
         (struct igraph_i_graphml_parser_state*)state0;
     va_list ap;
@@ -249,7 +249,7 @@
     va_end(ap);
 }
 
-xmlEntityPtr igraph_i_graphml_sax_handler_get_entity(void *state0,
+static xmlEntityPtr igraph_i_graphml_sax_handler_get_entity(void *state0,
         const xmlChar* name) {
     xmlEntityPtr predef = xmlGetPredefinedEntity(name);
     IGRAPH_UNUSED(state0);
@@ -260,7 +260,7 @@
     return blankEntity;
 }
 
-void igraph_i_graphml_handle_unknown_start_tag(struct igraph_i_graphml_parser_state *state) {
+static void igraph_i_graphml_handle_unknown_start_tag(struct igraph_i_graphml_parser_state *state) {
     if (state->st != UNKNOWN) {
         igraph_vector_int_push_back(&state->prev_state_stack, state->st);
         state->st = UNKNOWN;
@@ -270,7 +270,7 @@
     }
 }
 
-void igraph_i_graphml_sax_handler_start_document(void *state0) {
+static void igraph_i_graphml_sax_handler_start_document(void *state0) {
     struct igraph_i_graphml_parser_state *state =
         (struct igraph_i_graphml_parser_state*)state0;
     int ret;
@@ -359,7 +359,7 @@
     IGRAPH_FINALLY(igraph_i_graphml_destroy_state, state);
 }
 
-void igraph_i_graphml_sax_handler_end_document(void *state0) {
+static void igraph_i_graphml_sax_handler_end_document(void *state0) {
     struct igraph_i_graphml_parser_state *state =
         (struct igraph_i_graphml_parser_state*)state0;
     long i, l;
@@ -559,9 +559,9 @@
 #define XML_ATTR_VALUE_END(it) (*(it+4))
 #define XML_ATTR_VALUE(it) *(it+3), (*(it+4))-(*(it+3))
 
-igraph_i_graphml_attribute_record_t* igraph_i_graphml_add_attribute_key(
-    const xmlChar** attrs, int nb_attrs,
-    struct igraph_i_graphml_parser_state *state) {
+static igraph_i_graphml_attribute_record_t* igraph_i_graphml_add_attribute_key(
+        const xmlChar** attrs, int nb_attrs,
+        struct igraph_i_graphml_parser_state *state) {
     xmlChar **it;
     xmlChar *localname;
     igraph_trie_t *trie = 0;
@@ -749,10 +749,10 @@
     return rec;
 }
 
-void igraph_i_graphml_attribute_data_setup(struct igraph_i_graphml_parser_state *state,
-        const xmlChar **attrs,
-        int nb_attrs,
-        igraph_attribute_elemtype_t type) {
+static void igraph_i_graphml_attribute_data_setup(struct igraph_i_graphml_parser_state *state,
+                                                  const xmlChar **attrs,
+                                                  int nb_attrs,
+                                                  igraph_attribute_elemtype_t type) {
     xmlChar **it;
     int i;
 
@@ -782,8 +782,8 @@
     }
 }
 
-void igraph_i_graphml_append_to_data_char(struct igraph_i_graphml_parser_state *state,
-        const xmlChar *data, int len) {
+static void igraph_i_graphml_append_to_data_char(struct igraph_i_graphml_parser_state *state,
+                                                 const xmlChar *data, int len) {
     long int data_char_new_start = 0;
 
     if (!state->successful) {
@@ -805,7 +805,7 @@
     state->data_char[data_char_new_start + len] = '\0';
 }
 
-void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state *state) {
+static void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state *state) {
     const char *key = fromXmlChar(state->data_key);
     igraph_attribute_elemtype_t type = state->data_type;
     igraph_trie_t *trie = 0;
@@ -930,8 +930,8 @@
     }
 }
 
-void igraph_i_graphml_attribute_default_value_finish(
-    struct igraph_i_graphml_parser_state *state) {
+static void igraph_i_graphml_attribute_default_value_finish(
+        struct igraph_i_graphml_parser_state *state) {
     igraph_i_graphml_attribute_record_t *graphmlrec = state->current_attr_record;
 
     if (graphmlrec == 0) {
@@ -971,10 +971,10 @@
     }
 }
 
-void igraph_i_graphml_sax_handler_start_element_ns(
-    void *state0, const xmlChar* localname, const xmlChar* prefix,
-    const xmlChar* uri, int nb_namespaces, const xmlChar** namespaces,
-    int nb_attributes, int nb_defaulted, const xmlChar** attributes) {
+static void igraph_i_graphml_sax_handler_start_element_ns(
+        void *state0, const xmlChar* localname, const xmlChar* prefix,
+        const xmlChar* uri, int nb_namespaces, const xmlChar** namespaces,
+        int nb_attributes, int nb_defaulted, const xmlChar** attributes) {
     struct igraph_i_graphml_parser_state *state =
         (struct igraph_i_graphml_parser_state*)state0;
     xmlChar** it;
@@ -1174,7 +1174,8 @@
     }
 }
 
-void igraph_i_graphml_sax_handler_end_element_ns(void *state0,
+static void igraph_i_graphml_sax_handler_end_element_ns(
+        void *state0,
         const xmlChar* localname, const xmlChar* prefix,
         const xmlChar* uri) {
     struct igraph_i_graphml_parser_state *state =
@@ -1232,7 +1233,7 @@
     }
 }
 
-void igraph_i_graphml_sax_handler_chars(void* state0, const xmlChar* ch, int len) {
+static void igraph_i_graphml_sax_handler_chars(void* state0, const xmlChar* ch, int len) {
     struct igraph_i_graphml_parser_state *state =
         (struct igraph_i_graphml_parser_state*)state0;
 
@@ -1294,7 +1295,7 @@
 
 #define IS_FORBIDDEN_CONTROL_CHAR(x) ((x) < ' ' && (x) != '\t' && (x) != '\r' && (x) != '\n')
 
-int igraph_i_xml_escape(char* src, char** dest) {
+static int igraph_i_xml_escape(char* src, char** dest) {
     long int destlen = 0;
     char *s, *d;
     unsigned char ch;
@@ -1353,13 +1354,13 @@
  * graphs. Currently only the most basic import functionality is implemented
  * in igraph: it can read GraphML files without nested graphs and hyperedges.
  * Attributes of the graph are loaded only if an attribute interface
- * is attached, ie. if you use igraph from R or Python.
+ * is attached, i.e. if you use igraph from R or Python.
  *
  * </para><para>
- * Graph attribute names are taken from the \c attr.name attributes of the
- * \c key tags in the GraphML file. Since \c attr.name is not mandatory,
+ * Graph attribute names are taken from the <code>attr.name</code> attributes of the
+ * \c key tags in the GraphML file. Since <code>attr.name</code> is not mandatory,
  * igraph will fall back to the \c id attribute of the \c key tag if
- * \c attr.name is missing.
+ * <code>attr.name</code> is missing.
  *
  * \param graph Pointer to an uninitialized graph object.
  * \param instream A stream, it should be readable.
diff --git a/igraph/src/foreign-lgl-lexer.c b/igraph/src/foreign-lgl-lexer.c
--- a/igraph/src/foreign-lgl-lexer.c
+++ b/igraph/src/foreign-lgl-lexer.c
@@ -485,16 +485,16 @@
 #include "foreign-lgl-parser.h"
 #define YY_EXTRA_TYPE igraph_i_lgl_parsedata_t*
 #define YY_USER_ACTION yylloc->first_line = yylineno;
-/* We assume that 'file' is 'stderr' here. */
 #ifdef USING_R
 #define fprintf(file, msg, ...) (1)
-#endif
+#define YY_FATAL_ERROR(msg)                                      \
+  igraph_error("Fatal error in LGL parser: " # msg, __FILE__,    \
+               __LINE__, IGRAPH_PARSEERROR);
 #ifdef stdout 
 #  undef stdout
 #endif
 #define stdout 0
-#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
-				__LINE__, IGRAPH_PARSEERROR);
+#endif
 #define YY_NO_INPUT 1
 #line 500 "foreign-lgl-lexer.c"
 
diff --git a/igraph/src/foreign-ncol-lexer.c b/igraph/src/foreign-ncol-lexer.c
--- a/igraph/src/foreign-ncol-lexer.c
+++ b/igraph/src/foreign-ncol-lexer.c
@@ -485,16 +485,16 @@
 #include "foreign-ncol-parser.h"
 #define YY_EXTRA_TYPE igraph_i_ncol_parsedata_t*
 #define YY_USER_ACTION yylloc->first_line = yylineno;
-/* We assume that 'file' is 'stderr' here. */
 #ifdef USING_R
 #define fprintf(file, msg, ...) (1)
-#endif
+#define YY_FATAL_ERROR(msg)                                       \
+  igraph_error("Fatal error in NCOL parser: " # msg, __FILE__,    \
+               __LINE__, IGRAPH_PARSEERROR);
 #ifdef stdout 
 #  undef stdout
 #endif
 #define stdout 0
-#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
-				__LINE__, IGRAPH_PARSEERROR);
+#endif
 #define YY_NO_INPUT 1
 #line 500 "foreign-ncol-lexer.c"
 
diff --git a/igraph/src/foreign-pajek-lexer.c b/igraph/src/foreign-pajek-lexer.c
--- a/igraph/src/foreign-pajek-lexer.c
+++ b/igraph/src/foreign-pajek-lexer.c
@@ -604,16 +604,16 @@
 #include "foreign-pajek-parser.h"
 #define YY_EXTRA_TYPE igraph_i_pajek_parsedata_t*
 #define YY_USER_ACTION yylloc->first_line = yylineno;
-/* We assume that 'file' is 'stderr' here. */
 #ifdef USING_R
 #define fprintf(file, msg, ...) (1)
-#endif
+#define YY_FATAL_ERROR(msg)                                        \
+  igraph_error("Fatal error in PAJEK parser: " # msg, __FILE__,    \
+               __LINE__, IGRAPH_PARSEERROR);
 #ifdef stdout 
 #  undef stdout
 #endif
 #define stdout 0
-#define exit(code) igraph_error("Fatal error in DL parser", __FILE__, \
-				__LINE__, IGRAPH_PARSEERROR);
+#endif
 #define YY_NO_INPUT 1
 #line 619 "foreign-pajek-lexer.c"
 
diff --git a/igraph/src/foreign-pajek-parser.c b/igraph/src/foreign-pajek-parser.c
--- a/igraph/src/foreign-pajek-parser.c
+++ b/igraph/src/foreign-pajek-parser.c
@@ -2690,7 +2690,7 @@
   if (tmp==0) {
     IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
   }
-  IGRAPH_FINALLY(free, tmp);
+  IGRAPH_FINALLY(igraph_free, tmp);
   strncpy(tmp, value, len);
   tmp[len]='\0';
 
@@ -2717,7 +2717,7 @@
   if (tmp==0) {
     IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
   }
-  IGRAPH_FINALLY(free, tmp);
+  IGRAPH_FINALLY(igraph_free, tmp);
   strncpy(tmp, value, len);
   tmp[len]='\0';
   
diff --git a/igraph/src/foreign.c b/igraph/src/foreign.c
--- a/igraph/src/foreign.c
+++ b/igraph/src/foreign.c
@@ -22,7 +22,6 @@
 */
 
 #include "igraph_foreign.h"
-#include "config.h"
 #include "igraph_math.h"
 #include "igraph_gml_tree.h"
 #include "igraph_memory.h"
@@ -31,6 +30,7 @@
 #include "igraph_interrupt_internal.h"
 #include "igraph_constructors.h"
 #include "igraph_types_internal.h"
+#include "config.h"
 
 #include <ctype.h>      /* isspace */
 #include <string.h>
@@ -53,10 +53,10 @@
  * \brief Reads an edge list from a file and creates a graph.
  *
  * </para><para>
- * This format is simply a series of even number integers separated by
- * whitespace. The one edge (ie. two integers) per line format is thus
- * not required (but recommended for readability). Edges of directed
- * graphs are assumed to be in from, to order.
+ * This format is simply a series of an even number of non-negative integers separated by
+ * whitespace. The integers represent vertex IDs. Placing each edge (i.e. pair of integers) 
+ * on a separate line is not required, but it is recommended for readability. 
+ * Edges of directed graphs are assumed to be in "from, to" order.
  * \param graph Pointer to an uninitialized graph object.
  * \param instream Pointer to a stream, it should be readable.
  * \param n The number of vertices in the graph. If smaller than the
@@ -485,7 +485,7 @@
  * project files (<filename>.paj</filename>) are not. These might be
  * supported in the future if there is need for it.
  * \oli Time events networks are not supported.
- * \oli Hypergraphs (ie. graphs with non-binary edges) are not
+ * \oli Hypergraphs (i.e. graphs with non-binary edges) are not
  * supported.
  * \oli Graphs with both directed and non-directed edges are not
  * supported, are they cannot be represented in
@@ -499,35 +499,35 @@
  * If there are attribute handlers installed,
  * <command>igraph</command> also reads the vertex and edge attributes
  * from the file. Most attributes are renamed to be more informative:
- * `\c color' instead of `\c c', `\c xfact' instead of `\c x_fact',
- * `\c yfact' instead of `y_fact', `\c labeldist' instead of `\c lr',
- * `\c labeldegree2' instead of `\c lphi', `\c framewidth' instead of `\c bw',
- * `\c fontsize'
- * instead of `\c fos', `\c rotation' instead of `\c phi', `\c radius' instead
- * of `\c r',
- * `\c diamondratio' instead of `\c q', `\c labeldegree' instead of `\c la',
- * `\c vertexsize'
- * instead of `\c size', `\c color' instead of `\c ic', `\c framecolor' instead of
- * `\c bc', `\c labelcolor' instead of `\c lc', these belong to vertices.
+ * \c color instead of \c c, \c xfact instead of \c x_fact,
+ * \c yfact instead of y_fact, \c labeldist instead of \c lr,
+ * \c labeldegree2 instead of \c lphi, \c framewidth instead of \c bw,
+ * \c fontsize
+ * instead of \c fos, \c rotation instead of \c phi, \c radius instead
+ * of \c r,
+ * \c diamondratio instead of \c q, \c labeldegree instead of \c la,
+ * \c vertexsize
+ * instead of \c size, \c color instead of \c ic, \c framecolor instead of
+ * \c bc, \c labelcolor instead of \c lc, these belong to vertices.
  *
  * </para><para>
- * Edge attributes are also renamed, `\c s' to `\c arrowsize', `\c w'
- * to `\c edgewidth', `\c h1' to `\c hook1', `\c h2' to `\c hook2',
- * `\c a1' to `\c angle1', `\c a2' to `\c angle2', `\c k1' to
- * `\c velocity1', `\c k2' to `\c velocity2', `\c ap' to `\c
- * arrowpos', `\c lp' to `\c labelpos', `\c lr' to
- * `\c labelangle', `\c lphi' to `\c labelangle2', `\c la' to `\c
- * labeldegree', `\c fos' to
- * `\c fontsize', `\c a' to `\c arrowtype', `\c p' to `\c
- * linepattern', `\c l' to `\c label', `\c lc' to
- * `\c labelcolor', `\c c' to `\c color'.
+ * Edge attributes are also renamed, \c s to \c arrowsize, \c w
+ * to \c edgewidth, \c h1 to \c hook1, \c h2 to \c hook2,
+ * \c a1 to \c angle1, \c a2 to \c angle2, \c k1 to
+ * \c velocity1, \c k2 to \c velocity2, \c ap to \c
+ * arrowpos, \c lp to \c labelpos, \c lr to
+ * \c labelangle, \c lphi to \c labelangle2, \c la to \c
+ * labeldegree, \c fos to
+ * \c fontsize, \c a to \c arrowtype, \c p to \c
+ * linepattern, \c l to \c label, \c lc to
+ * \c labelcolor, \c c to \c color.
  *
  * </para><para>
- * In addition the following vertex attributes might be added: `\c id'
- * if there are vertex ids in the file, `\c x' and `\c y' or `\c x'
- * and `\c y' and `\c z' if there are vertex coordinates in the file.
+ * In addition the following vertex attributes might be added: \c id
+ * if there are vertex ids in the file, \c x and \c y or \c x
+ * and \c y and \c z if there are vertex coordinates in the file.
  *
- * </para><para>The `\c weight' edge attribute might be
+ * </para><para>The \c weight edge attribute might be
  * added if there are edge weights present.
  *
  * </para><para>
@@ -878,7 +878,7 @@
     return 0;
 }
 
-int igraph_i_read_graph_graphdb_getword(FILE *instream) {
+static int igraph_i_read_graph_graphdb_getword(FILE *instream) {
     int b1, b2;
     unsigned char c1, c2;
     b1 = fgetc(instream);
@@ -977,7 +977,7 @@
 int igraph_gml_yyparse (igraph_i_gml_parsedata_t* context);
 void igraph_gml_yyset_in  (FILE * in_str, void* yyscanner );
 
-void igraph_i_gml_destroy_attrs(igraph_vector_ptr_t **ptr) {
+static void igraph_i_gml_destroy_attrs(igraph_vector_ptr_t **ptr) {
     long int i;
     igraph_vector_ptr_t *vec;
     for (i = 0; i < 3; i++) {
@@ -1005,7 +1005,7 @@
     }
 }
 
-igraph_real_t igraph_i_gml_toreal(igraph_gml_tree_t *node, long int pos) {
+static igraph_real_t igraph_i_gml_toreal(igraph_gml_tree_t *node, long int pos) {
 
     igraph_real_t value = 0.0;
     int type = igraph_gml_tree_type(node, pos);
@@ -1025,10 +1025,10 @@
     return value;
 }
 
-const char *igraph_i_gml_tostring(igraph_gml_tree_t *node, long int pos) {
+static const char *igraph_i_gml_tostring(igraph_gml_tree_t *node, long int pos) {
 
     int type = igraph_gml_tree_type(node, pos);
-    char tmp[256];
+    static char tmp[256];
     const char *p = tmp;
     long int i;
     igraph_real_t d;
@@ -1155,7 +1155,7 @@
     }
     gtree = igraph_gml_tree_get_tree(context.tree, gidx);
 
-    IGRAPH_FINALLY(igraph_i_gml_destroy_attrs, &attrs);
+    IGRAPH_FINALLY(igraph_i_gml_destroy_attrs, attrs);
     igraph_vector_ptr_init(&gattrs, 0);
     igraph_vector_ptr_init(&vattrs, 0);
     igraph_vector_ptr_init(&eattrs, 0);
@@ -1942,7 +1942,7 @@
 #define E_COLOR            22
 #define E_LAST             23
 
-int igraph_i_pajek_escape(char* src, char** dest) {
+static int igraph_i_pajek_escape(char* src, char** dest) {
     long int destlen = 0;
     igraph_bool_t need_escape = 0;
 
@@ -2010,18 +2010,30 @@
  * the attributes of the vertices and edges, of course this requires
  * an attribute handler to be installed. The names of the
  * corresponding vertex and edge attributes are listed at \ref
- * igraph_read_graph_pajek(), eg. the `\c color' vertex attributes
- * determines the color (`\c c' in Pajek) parameter.
+ * igraph_read_graph_pajek(), eg. the \c color vertex attributes
+ * determines the color (\c c in Pajek) parameter.
  *
  * </para><para>
  * As of version 0.6.1 igraph writes bipartite graphs into Pajek files
  * correctly, i.e. they will be also bipartite when read into Pajek.
- * As Pajek is less flexible for bipartite graphs (the numeric ids of
+ * As Pajek is less flexible for bipartite graphs (the numeric IDs of
  * the vertices must be sorted according to vertex type), igraph might
  * need to reorder the vertices when writing a bipartite Pajek file.
- * This effectively means that numeric vertex ids usually change when
+ * This effectively means that numeric vertex IDs usually change when
  * a bipartite graph is written to a Pajek file, and then read back
  * into igraph.
+ *
+ * </para><para>
+ * Early versions of Pajek supported only Windows-style line endings
+ * in Pajek files, but recent versions support both Windows and Unix
+ * line endings. igraph therefore uses the platform-native line endings
+ * when the input file is opened in text mode, and uses Unix-style
+ * line endings when the input file is opened in binary mode. If you
+ * are using an old version of Pajek, you are on Unix and you are having
+ * problems reading files written by igraph on a Windows machine, convert the
+ * line endings manually with a text editor or with \c unix2dos or \c iconv
+ * from the command line).
+ *
  * \param graph The graph object to write.
  * \param outstream The file to write to. It should be opened and
  * writable. Make sure that you open the file in binary format if you use MS Windows,
@@ -2091,7 +2103,10 @@
                               };
     const char *estrnames2[] = { "a", "p", "l", "lc", "c" };
 
-    const char *newline = "\x0d\x0a";
+    /* Newer Pajek versions support both Unix and Windows-style line endings,
+     * so we just use Unix style. This will get converted to CRLF on Windows
+     * when the file is opened in text mode */
+    const char *newline = "\n";
 
     igraph_es_t es;
     igraph_eit_t eit;
@@ -2466,7 +2481,7 @@
     return 0;
 }
 
-int igraph_i_gml_convert_to_key(const char *orig, char **key) {
+static int igraph_i_gml_convert_to_key(const char *orig, char **key) {
     int no = 1;
     char strno[50];
     size_t i, len = strlen(orig), newlen = 0, plen = 0;
@@ -2741,7 +2756,7 @@
     return 0;
 }
 
-int igraph_i_dot_escape(const char *orig, char **result) {
+static int igraph_i_dot_escape(const char *orig, char **result) {
     /* do we have to escape the string at all? */
     long int i, j, len = (long int) strlen(orig), newlen = 0;
     igraph_bool_t need_quote = 0, is_number = 1;
@@ -3386,5 +3401,3 @@
 }
 
 #undef CHECK
-
-
diff --git a/igraph/src/forestfire.c b/igraph/src/forestfire.c
--- a/igraph/src/forestfire.c
+++ b/igraph/src/forestfire.c
@@ -38,7 +38,7 @@
 } igraph_i_forest_fire_data_t;
 
 
-void igraph_i_forest_fire_free(igraph_i_forest_fire_data_t *data) {
+static void igraph_i_forest_fire_free(igraph_i_forest_fire_data_t *data) {
     long int i;
     for (i = 0; i < data->no_of_nodes; i++) {
         igraph_vector_destroy(data->inneis + i);
@@ -117,21 +117,20 @@
     igraph_real_t param_geom_out = 1 - fw_prob;
     igraph_real_t param_geom_in = 1 - fw_prob * bw_factor;
 
-    if (fw_prob < 0) {
-        IGRAPH_ERROR("Forest fire model: 'fw_prob' should be between non-negative",
+    if (fw_prob < 0 || fw_prob >= 1) {
+        IGRAPH_ERROR("Forest fire model: 'fw_prob' must satisfy 0 <= fw_prob < 1.",
                      IGRAPH_EINVAL);
     }
-    if (bw_factor < 0) {
-        IGRAPH_ERROR("Forest fire model: 'bw_factor' should be non-negative",
+    if (bw_factor * fw_prob < 0 || bw_factor * fw_prob >= 1) {
+        IGRAPH_ERROR("Forest fire model: 'bw_factor' must satisfy 0 <= bw_factor * fw_prob < 1.",
                      IGRAPH_EINVAL);
     }
     if (ambs < 0) {
-        IGRAPH_ERROR("Number of ambassadors ('ambs') should be non-negative",
+        IGRAPH_ERROR("Forest fire model: Number of ambassadors must not be negative.",
                      IGRAPH_EINVAL);
     }
 
-    if (fw_prob == 0 || ambs == 0) {
-        IGRAPH_WARNING("'fw_prob or ambs is zero, creating empty graph");
+    if (ambs == 0) {
         IGRAPH_CHECK(igraph_empty(graph, nodes, directed));
         return 0;
     }
diff --git a/igraph/src/fortran_intrinsics.c b/igraph/src/fortran_intrinsics.c
--- a/igraph/src/fortran_intrinsics.c
+++ b/igraph/src/fortran_intrinsics.c
@@ -23,31 +23,31 @@
 
 #include <float.h>
 
-double digitsdbl_(double x) {
+double digitsdbl_(double *x) {
     return (double) DBL_MANT_DIG;
 }
 
-double epsilondbl_(double x) {
+double epsilondbl_(double *x) {
     return DBL_EPSILON;
 }
 
-double hugedbl_(double x) {
+double hugedbl_(double *x) {
     return DBL_MAX;
 }
 
-double tinydbl_(double x) {
+double tinydbl_(double *x) {
     return DBL_MIN;
 }
 
-int maxexponentdbl_(double x) {
+int maxexponentdbl_(double *x) {
     return DBL_MAX_EXP;
 }
 
-int minexponentdbl_(double x) {
+int minexponentdbl_(double *x) {
     return DBL_MIN_EXP;
 }
 
-double radixdbl_(double x) {
+double radixdbl_(double *x) {
     return (double) FLT_RADIX;
 }
 
diff --git a/igraph/src/games.c b/igraph/src/games.c
--- a/igraph/src/games.c
+++ b/igraph/src/games.c
@@ -47,8 +47,8 @@
     igraph_psumtree_t *sumtrees;
 } igraph_i_citing_cited_type_game_struct_t;
 
-void igraph_i_citing_cited_type_game_free (
-    igraph_i_citing_cited_type_game_struct_t *s);
+static void igraph_i_citing_cited_type_game_free (
+        igraph_i_citing_cited_type_game_struct_t *s);
 /**
  * \section about_games
  *
@@ -56,39 +56,39 @@
  * they generate a different graph every time you call them. </para>
  */
 
-int igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n,
-                               igraph_integer_t m,
-                               const igraph_vector_t *outseq,
-                               igraph_bool_t outpref,
-                               igraph_bool_t directed,
-                               const igraph_t *start_from);
+static int igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n,
+                                      igraph_integer_t m,
+                                      const igraph_vector_t *outseq,
+                                      igraph_bool_t outpref,
+                                      igraph_bool_t directed,
+                                      const igraph_t *start_from);
 
-int igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph,
-        igraph_integer_t n,
-        igraph_real_t power,
-        igraph_integer_t m,
-        const igraph_vector_t *outseq,
-        igraph_bool_t outpref,
-        igraph_real_t A,
-        igraph_bool_t directed,
-        const igraph_t *start_from);
+static int igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph,
+                                                    igraph_integer_t n,
+                                                    igraph_real_t power,
+                                                    igraph_integer_t m,
+                                                    const igraph_vector_t *outseq,
+                                                    igraph_bool_t outpref,
+                                                    igraph_real_t A,
+                                                    igraph_bool_t directed,
+                                                    const igraph_t *start_from);
 
-int igraph_i_barabasi_game_psumtree(igraph_t *graph,
-                                    igraph_integer_t n,
-                                    igraph_real_t power,
-                                    igraph_integer_t m,
-                                    const igraph_vector_t *outseq,
-                                    igraph_bool_t outpref,
-                                    igraph_real_t A,
-                                    igraph_bool_t directed,
-                                    const igraph_t *start_from);
+static int igraph_i_barabasi_game_psumtree(igraph_t *graph,
+                                           igraph_integer_t n,
+                                           igraph_real_t power,
+                                           igraph_integer_t m,
+                                           const igraph_vector_t *outseq,
+                                           igraph_bool_t outpref,
+                                           igraph_real_t A,
+                                           igraph_bool_t directed,
+                                           const igraph_t *start_from);
 
-int igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n,
-                               igraph_integer_t m,
-                               const igraph_vector_t *outseq,
-                               igraph_bool_t outpref,
-                               igraph_bool_t directed,
-                               const igraph_t *start_from) {
+static int igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n,
+                                      igraph_integer_t m,
+                                      const igraph_vector_t *outseq,
+                                      igraph_bool_t outpref,
+                                      igraph_bool_t directed,
+                                      const igraph_t *start_from) {
 
     long int no_of_nodes = n;
     long int no_of_neighbors = m;
@@ -124,7 +124,7 @@
     if (bag == 0) {
         IGRAPH_ERROR("barabasi_game failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, bag);    /* TODO: hack */
+    IGRAPH_FINALLY(igraph_free, bag);
 
     /* The first node(s) in the bag */
     if (start_from) {
@@ -190,15 +190,15 @@
     return 0;
 }
 
-int igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph,
-        igraph_integer_t n,
-        igraph_real_t power,
-        igraph_integer_t m,
-        const igraph_vector_t *outseq,
-        igraph_bool_t outpref,
-        igraph_real_t A,
-        igraph_bool_t directed,
-        const igraph_t *start_from) {
+static int igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph,
+                                                    igraph_integer_t n,
+                                                    igraph_real_t power,
+                                                    igraph_integer_t m,
+                                                    const igraph_vector_t *outseq,
+                                                    igraph_bool_t outpref,
+                                                    igraph_real_t A,
+                                                    igraph_bool_t directed,
+                                                    const igraph_t *start_from) {
 
     long int no_of_nodes = n;
     long int no_of_neighbors = m;
@@ -296,15 +296,15 @@
     return 0;
 }
 
-int igraph_i_barabasi_game_psumtree(igraph_t *graph,
-                                    igraph_integer_t n,
-                                    igraph_real_t power,
-                                    igraph_integer_t m,
-                                    const igraph_vector_t *outseq,
-                                    igraph_bool_t outpref,
-                                    igraph_real_t A,
-                                    igraph_bool_t directed,
-                                    const igraph_t *start_from) {
+static int igraph_i_barabasi_game_psumtree(igraph_t *graph,
+                                           igraph_integer_t n,
+                                           igraph_real_t power,
+                                           igraph_integer_t m,
+                                           const igraph_vector_t *outseq,
+                                           igraph_bool_t outpref,
+                                           igraph_real_t A,
+                                           igraph_bool_t directed,
+                                           const igraph_t *start_from) {
 
     long int no_of_nodes = n;
     long int no_of_neighbors = m;
@@ -437,7 +437,7 @@
  *        no outgoing edges, so the first number in this vector is
  *        ignored.
  * \param outpref Boolean, if true not only the in- but also the out-degree
- *        of a vertex increases its citation probability. Ie. the
+ *        of a vertex increases its citation probability. I.e., the
  *        citation probability is determined by the total degree of
  *        the vertices. Ignored and assumed to be true if the graph
  *        being generated is undirected.
@@ -860,7 +860,7 @@
     if (bag1 == 0) {
         IGRAPH_ERROR("degree sequence game (simple)", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, bag1);   /* TODO: hack */
+    IGRAPH_FINALLY(igraph_free, bag1);
 
     for (i = 0; i < no_of_nodes; i++) {
         for (j = 0; j < VECTOR(*out_seq)[i]; j++) {
@@ -872,7 +872,7 @@
         if (bag2 == 0) {
             IGRAPH_ERROR("degree sequence game (simple)", IGRAPH_ENOMEM);
         }
-        IGRAPH_FINALLY(free, bag2);
+        IGRAPH_FINALLY(igraph_free, bag2);
         for (i = 0; i < no_of_nodes; i++) {
             for (j = 0; j < VECTOR(*in_seq)[i]; j++) {
                 bag2[bagp2++] = i;
@@ -965,6 +965,8 @@
      * until it finally succeeds. */
     finished = 0;
     while (!finished) {
+        IGRAPH_ALLOW_INTERRUPTION();
+
         /* Be optimistic :) */
         failed = 0;
 
@@ -1111,6 +1113,8 @@
      * until it finally succeeds. */
     finished = 0;
     while (!finished) {
+        IGRAPH_ALLOW_INTERRUPTION();
+
         /* Be optimistic :) */
         failed = 0;
 
@@ -1210,15 +1214,24 @@
     return IGRAPH_SUCCESS;
 }
 
+/* swap two elements of a vector_int */
+#define SWAP_INT_ELEM(vec, i, j) \
+    { \
+        igraph_integer_t temp; \
+        temp = VECTOR(vec)[i]; \
+        VECTOR(vec)[i] = VECTOR(vec)[j]; \
+        VECTOR(vec)[j] = temp; \
+    }
+
 int igraph_degree_sequence_game_no_multiple_undirected_uniform(igraph_t *graph, const igraph_vector_t *degseq) {
     igraph_vector_int_t stubs;
     igraph_vector_t edges;
     igraph_bool_t degseq_ok;
     igraph_vector_ptr_t adjlist;
-    long i, j, k;
+    long i, j;
     long vcount, ecount, stub_count;
 
-    IGRAPH_CHECK(igraph_is_graphical_degree_sequence(degseq, 0, &degseq_ok));
+    IGRAPH_CHECK(igraph_is_graphical_degree_sequence(degseq, NULL, &degseq_ok));
     if (!degseq_ok) {
         IGRAPH_ERROR("No simple undirected graph can realize the given degree sequence", IGRAPH_EINVAL);
     }
@@ -1230,16 +1243,21 @@
     IGRAPH_VECTOR_INT_INIT_FINALLY(&stubs, stub_count);
     IGRAPH_VECTOR_INIT_FINALLY(&edges, stub_count);
 
-    k = 0;
-    for (i = 0; i < vcount; ++i) {
-        long deg = (long) VECTOR(*degseq)[i];
-        for (j = 0; j < deg; ++j) {
-            VECTOR(stubs)[k++] = i;
+    /* Fill stubs vector. */
+    {
+        long k = 0;
+        for (i = 0; i < vcount; ++i) {
+            long deg = (long) VECTOR(*degseq)[i];
+            for (j = 0; j < deg; ++j) {
+                VECTOR(stubs)[k++] = i;
+            }
         }
     }
 
+    /* Build an adjacency list in terms of sets; used to check for multi-edges. */
     IGRAPH_CHECK(igraph_vector_ptr_init(&adjlist, vcount));
     IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&adjlist, igraph_set_destroy);
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist);
     for (i = 0; i < vcount; ++i) {
         igraph_set_t *set = igraph_malloc(sizeof(igraph_set_t));
         if (! set) {
@@ -1248,21 +1266,28 @@
         IGRAPH_CHECK(igraph_set_init(set, 0));
         VECTOR(adjlist)[i] = set;
         IGRAPH_CHECK(igraph_set_reserve(set, (long) VECTOR(*degseq)[i]));
-    }
-    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist);
+    }    
 
     RNG_BEGIN();
 
     for (;;) {
         igraph_bool_t success = 1;
-        IGRAPH_CHECK(igraph_vector_int_shuffle(&stubs));
 
+        /* Shuffle stubs vector with Fisher-Yates and check for self-loops and multi-edges as we go. */
         for (i = 0; i < ecount; ++i) {
-            igraph_integer_t from = VECTOR(stubs)[2 * i];
-            igraph_integer_t to = VECTOR(stubs)[2 * i + 1];
+            long k, from, to;
 
-            /* loop edge, fail */
-            if (to == from) {
+            k = RNG_INTEGER(2*i, stub_count-1);
+            SWAP_INT_ELEM(stubs, 2*i, k);
+
+            k = RNG_INTEGER(2*i+1, stub_count-1);
+            SWAP_INT_ELEM(stubs, 2*i+1, k);
+
+            from = VECTOR(stubs)[2*i];
+            to   = VECTOR(stubs)[2*i+1];
+
+            /* self-loop, fail */
+            if (from == to) {
                 success = 0;
                 break;
             }
@@ -1286,11 +1311,12 @@
             break;
         }
 
-        IGRAPH_ALLOW_INTERRUPTION();
-
+        /* Clear adjacency list. */
         for (j = 0; j < vcount; ++j) {
             igraph_set_clear((igraph_set_t *) VECTOR(adjlist)[j]);
         }
+
+        IGRAPH_ALLOW_INTERRUPTION();
     }
 
     RNG_END();
@@ -1307,13 +1333,14 @@
     return IGRAPH_SUCCESS;
 }
 
+
 int igraph_degree_sequence_game_no_multiple_directed_uniform(
     igraph_t *graph, const igraph_vector_t *out_deg, const igraph_vector_t *in_deg) {
     igraph_vector_int_t out_stubs, in_stubs;
     igraph_vector_t edges;
     igraph_bool_t degseq_ok;
     igraph_vector_ptr_t adjlist;
-    long i, j, k, l;
+    long i, j;
     long vcount, ecount;
 
     IGRAPH_CHECK(igraph_is_graphical_degree_sequence(out_deg, in_deg, &degseq_ok));
@@ -1328,23 +1355,28 @@
     IGRAPH_VECTOR_INT_INIT_FINALLY(&in_stubs, ecount);
     IGRAPH_VECTOR_INIT_FINALLY(&edges, 2 * ecount);
 
-    k = 0; l = 0;
-    for (i = 0; i < vcount; ++i) {
-        long dout, din;
+    /* Fill in- and out-stubs vectors. */
+    {
+        long k = 0, l = 0;
+        for (i = 0; i < vcount; ++i) {
+            long dout, din;
 
-        dout = (long) VECTOR(*out_deg)[i];
-        for (j = 0; j < dout; ++j) {
-            VECTOR(out_stubs)[k++] = i;
-        }
+            dout = (long) VECTOR(*out_deg)[i];
+            for (j = 0; j < dout; ++j) {
+                VECTOR(out_stubs)[k++] = i;
+            }
 
-        din  = (long) VECTOR(*in_deg)[i];
-        for (j = 0; j < din; ++j) {
-            VECTOR(in_stubs)[l++] = i;
+            din  = (long) VECTOR(*in_deg)[i];
+            for (j = 0; j < din; ++j) {
+                VECTOR(in_stubs)[l++] = i;
+            }
         }
     }
 
+    /* Build an adjacency list in terms of sets; used to check for multi-edges. */
     IGRAPH_CHECK(igraph_vector_ptr_init(&adjlist, vcount));
     IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&adjlist, igraph_set_destroy);
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist);
     for (i = 0; i < vcount; ++i) {
         igraph_set_t *set = igraph_malloc(sizeof(igraph_set_t));
         if (! set) {
@@ -1353,21 +1385,25 @@
         IGRAPH_CHECK(igraph_set_init(set, 0));
         VECTOR(adjlist)[i] = set;
         IGRAPH_CHECK(igraph_set_reserve(set, (long) VECTOR(*out_deg)[i]));
-    }
-    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist);
+    }    
 
     RNG_BEGIN();
 
     for (;;) {
         igraph_bool_t success = 1;
-        IGRAPH_CHECK(igraph_vector_int_shuffle(&out_stubs));
 
+        /* Shuffle out-stubs vector with Fisher-Yates and check for self-loops and multi-edges as we go. */
         for (i = 0; i < ecount; ++i) {
-            igraph_integer_t from = VECTOR(out_stubs)[i];
-            igraph_integer_t to = VECTOR(in_stubs)[i];
+            long k, from, to;
             igraph_set_t *set;
 
-            /* loop edge, fail */
+            k = RNG_INTEGER(i, ecount-1);
+            SWAP_INT_ELEM(out_stubs, i, k);
+
+            from = VECTOR(out_stubs)[i];
+            to   = VECTOR(in_stubs)[i];
+
+            /* self-loop, fail */
             if (to == from) {
                 success = 0;
                 break;
@@ -1392,11 +1428,12 @@
             break;
         }
 
-        IGRAPH_ALLOW_INTERRUPTION();
-
+        /* Clear adjacency list. */
         for (j = 0; j < vcount; ++j) {
             igraph_set_clear((igraph_set_t *) VECTOR(adjlist)[j]);
         }
+
+        IGRAPH_ALLOW_INTERRUPTION();
     }
 
     RNG_END();
@@ -1414,6 +1451,9 @@
     return IGRAPH_SUCCESS;
 }
 
+#undef SWAP_INT_ELEM
+
+
 /* This is in gengraph_mr-connected.cpp */
 
 int igraph_degree_sequence_game_vl(igraph_t *graph,
@@ -1426,9 +1466,9 @@
  *
  * \param graph Pointer to an uninitialized graph object.
  * \param out_deg The degree sequence for an undirected graph (if
- *        \p in_seq is of length zero), or the out-degree
+ *        \p in_seq is \c NULL or of length zero), or the out-degree
  *        sequence of a directed graph (if \p in_deq is not
- *        of length zero.
+ *        of length zero).
  * \param in_deg It is either a zero-length vector or
  *        \c NULL (if an undirected
  *        graph is generated), or the in-degree sequence.
@@ -1439,34 +1479,36 @@
  *          For undirected graphs, it puts all vertex IDs in a bag
  *          such that the multiplicity of a vertex in the bag is the same as
  *          its degree. Then it draws pairs from the bag until the bag becomes
- *          empty. This method can generate both loop (self) edges and multiple
+ *          empty. This method may generate both loop (self) edges and multiple
  *          edges. For directed graphs, the algorithm is basically the same,
  *          but two separate bags are used for the in- and out-degrees.
  *          Undirected graphs are generated with probability proportional to
  *          <code>(\prod_{i&lt;j} A_{ij} ! \prod_i A_{ii} !!)^{-1}</code>,
  *          where \c A denotes the adjacency matrix and <code>!!</code> denotes
- *          the double factorial.
- *          The corresponding  expression for directed ones is
+ *          the double factorial. Here \c A is assumed to have twice the number of
+ *          self-loops on its diagonal.
+ *          The corresponding  expression for directed graphs is
  *          <code>(\prod_{i,j} A_{ij}!)^{-1}</code>.
  *          Thus the probability of all simple graphs (which only have 0s and 1s
  *          in the adjacency matrix) is the same, while that of
- *          non-simple ones depends on their structure.
+ *          non-simple ones depends on their edge and self-loop multiplicities.
  *          \cli IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE
- *          This method is similar to \c IGRAPH_DEGSEQ_SIMPLE
+ *          This method generates simple graphs.
+ *          It is similar to \c IGRAPH_DEGSEQ_SIMPLE
  *          but tries to avoid multiple and loop edges and restarts the
- *          generation from scratch if it gets stuck. It is not guaranteed
- *          to sample uniformly from the space of all possible graphs with
- *          the given sequence, but it is relatively fast and it will
+ *          generation from scratch if it gets stuck. It can generate all simple
+ *          realizations of a degree sequence, but it is not guaranteed
+ *          to sample them uniformly. This method is relatively fast and it will
  *          eventually succeed if the provided degree sequence is graphical,
  *          but there is no upper bound on the number of iterations.
  *          \cli IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE_UNIFORM
  *          This method is identical to \c IGRAPH_DEGSEQ_SIMPLE, but if the
  *          generated graph is not simple, it rejects it and re-starts the
- *          generation. It samples all simple graphs with the same probability.
+ *          generation. It generates all simple graphs with the same probability.
  *          \cli IGRAPH_DEGSEQ_VL
- *          This method is a much more sophisticated generator than the
- *          previous ones. It can sample undirected, connected simple graphs
- *          uniformly and uses Monte-Carlo methods to randomize the graphs.
+ *          This method samples undirected connected graphs approximately
+ *          uniformly. It is a Monte Carlo method based on degree-preserving
+ *          edge swaps.
  *          This generator should be favoured if undirected and connected
  *          graphs are to be generated and execution time is not a concern.
  *          igraph uses the original implementation of Fabien Viger; for the algorithm,
@@ -1540,7 +1582,7 @@
  * growing) random graphs.
  * \param graph Uninitialized graph object.
  * \param n The number of vertices in the graph.
- * \param m The number of edges to add in a time step (ie. after
+ * \param m The number of edges to add in a time step (i.e. after
  *        adding a vertex).
  * \param directed Boolean, whether to generate a directed graph.
  * \param citation Boolean, if \c TRUE, the edges always
@@ -2268,7 +2310,7 @@
  * \param nodes The number of vertices in the graph.
  * \param radius The radius within which the vertices will be connected.
  * \param torus Logical constant, if true periodic boundary conditions
- *        will be used, ie. the vertices are assumed to be on a torus
+ *        will be used, i.e. the vertices are assumed to be on a torus
  *        instead of a square.
  * \return Error code.
  *
@@ -2382,9 +2424,7 @@
 }
 
 
-void igraph_i_preference_game_free_vids_by_type(igraph_vector_ptr_t *vecs);
-
-void igraph_i_preference_game_free_vids_by_type(igraph_vector_ptr_t *vecs) {
+static void igraph_i_preference_game_free_vids_by_type(igraph_vector_ptr_t *vecs) {
     int i = 0, n;
     igraph_vector_t *v;
 
@@ -2926,13 +2966,9 @@
     return 0;
 }
 
-int igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_real_t prob,
-                                      igraph_bool_t loops,
-                                      igraph_vector_t *edges);
-
-int igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_real_t prob,
-                                      igraph_bool_t loops,
-                                      igraph_vector_t *edges) {
+static int igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_real_t prob,
+                                             igraph_bool_t loops,
+                                             igraph_vector_t *edges) {
 
     int no_verts = igraph_vcount(graph);
     int no_edges = igraph_ecount(graph);
@@ -3386,7 +3422,7 @@
  *
  * </para><para>
  * The \p preference argument specifies the preferences for the
- * citation lags, ie. its first elements contains the attractivity
+ * citation lags, i.e. its first elements contains the attractivity
  * of the very recently cited vertices, etc. The last element is
  * special, it contains the attractivity of the vertices which were
  * never cited. This element should be bigger than zero.
@@ -3627,7 +3663,7 @@
     return 0;
 }
 
-void igraph_i_citing_cited_type_game_free(igraph_i_citing_cited_type_game_struct_t *s) {
+static void igraph_i_citing_cited_type_game_free(igraph_i_citing_cited_type_game_struct_t *s) {
     long int i;
     if (!s->sumtrees) {
         return;
@@ -3651,7 +3687,7 @@
  * category of both the citing and the cited vertex and is given in
  * the \p pref matrix. The categories of the citing vertex correspond
  * to the rows, the categories of the cited vertex to the columns of
- * this matrix. Ie. the element in row \c i and column \c j gives the
+ * this matrix. I.e. the element in row \c i and column \c j gives the
  * probability that a \c j vertex is cited, if the category of the
  * citing vertex is \c i.
  *
@@ -3783,16 +3819,15 @@
  *
  */
 int igraph_simple_interconnected_islands_game(
-    igraph_t        *graph,
-    igraph_integer_t    islands_n,
-    igraph_integer_t    islands_size,
-    igraph_real_t       islands_pin,
-    igraph_integer_t    n_inter) {
+        igraph_t *graph,
+        igraph_integer_t islands_n,
+        igraph_integer_t islands_size,
+        igraph_real_t islands_pin,
+        igraph_integer_t n_inter) {
 
 
     igraph_vector_t edges = IGRAPH_VECTOR_NULL;
     igraph_vector_t s = IGRAPH_VECTOR_NULL;
-    int retval = 0;
     int nbNodes;
     double maxpossibleedgesPerIsland;
     double maxedgesPerIsland;
@@ -3816,73 +3851,63 @@
         IGRAPH_ERROR("Invalid number of inter-islands links", IGRAPH_EINVAL);
     }
 
-    // how much memory ?
+    /* how much memory ? */
     nbNodes = islands_n * islands_size;
     maxpossibleedgesPerIsland = ((double)islands_size * ((double)islands_size - (double)1)) / (double)2;
     maxedgesPerIsland = islands_pin * maxpossibleedgesPerIsland;
     nbEdgesInterIslands = n_inter * (islands_n * (islands_n - 1)) / 2;
-    maxedges = maxedgesPerIsland * islands_n + nbEdgesInterIslands;
-
-    // debug&tests : printf("total nodes %d, maxedgesperisland %f, maxedgesinterislands %d, maxedges %f\n", nbNodes, maxedgesPerIsland, nbEdgesInterIslands, maxedges);
+    maxedges = maxedgesPerIsland * islands_n + nbEdgesInterIslands;    
 
-    // reserve enough place for all the edges, thanks !
+    /* reserve enough space for all the edges */
     IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
     IGRAPH_CHECK(igraph_vector_reserve(&edges, (long int) maxedges));
 
     RNG_BEGIN();
 
-    // first create all the islands
-    for (is = 1; is <= islands_n; is++) { // for each island
+    /* first create all the islands */
+    for (is = 1; is <= islands_n; is++) { /* for each island */
 
-        // index for start and end of nodes in this island
+        /* index for start and end of nodes in this island */
         startIsland = islands_size * (is - 1);
         endIsland = startIsland + islands_size - 1;
 
-
-        // debug&tests : printf("start %d,end %d\n", startIsland, endIsland);
-
-        // create the random numbers to be used (into s)
+        /* create the random numbers to be used (into s) */
         IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
         IGRAPH_CHECK(igraph_vector_reserve(&s, (long int) maxedgesPerIsland));
 
         last = RNG_GEOM(islands_pin);
-        // debug&tests : printf("last=%f \n", last);
-        while (last < maxpossibleedgesPerIsland) { // maxedgesPerIsland
+        while (last < maxpossibleedgesPerIsland) { /* maxedgesPerIsland */
             IGRAPH_CHECK(igraph_vector_push_back(&s, last));
             myrand = RNG_GEOM(islands_pin);
-            last += myrand; //RNG_GEOM(islands_pin);
-            //printf("myrand=%f , last=%f \n", myrand, last);
+            last += myrand; /* RNG_GEOM(islands_pin); */
             last += 1;
         }
 
 
 
-        // change this to edges !
+        /* change this to edges ! */
         for (i = 0; i < igraph_vector_size(&s); i++) {
-
             long int to = (long int) floor((sqrt(8 * VECTOR(s)[i] + 1) + 1) / 2);
             long int from = (long int) (VECTOR(s)[i] - (((igraph_real_t)to) * (to - 1)) / 2);
             to += startIsland;
             from += startIsland;
-            // debug&tests : printf("from %d to %d\n", from, to);
+
             igraph_vector_push_back(&edges, from);
             igraph_vector_push_back(&edges, to);
         }
 
-        // clear the memory used for random number for this island
+        /* clear the memory used for random number for this island */
         igraph_vector_destroy(&s);
         IGRAPH_FINALLY_CLEAN(1);
 
 
-        // create the links with other islands
-        for (i = is + 1; i <= islands_n; i++) { // for each other island (not the previous ones)
-
-            // debug&tests : printf("link islands %d and %d\n", is, i);
-            for (j = 0; j < n_inter; j++) { // for each link between islands
+        /* create the links with other islands */
+        for (i = is + 1; i <= islands_n; i++) { /* for each other island (not the previous ones) */
 
+            for (j = 0; j < n_inter; j++) { /* for each link between islands */
                 long int from = (long int) RNG_UNIF(startIsland, endIsland);
                 long int to = (long int) RNG_UNIF((i - 1) * islands_size, i * islands_size);
-                //printf("from %d to %d\n", from, to);
+
                 igraph_vector_push_back(&edges, from);
                 igraph_vector_push_back(&edges, to);
             }
@@ -3892,14 +3917,14 @@
 
     RNG_END();
 
-    // actually fill the graph object
-    IGRAPH_CHECK(retval = igraph_create(graph, &edges, nbNodes, 0));
+    /* actually fill the graph object */
+    IGRAPH_CHECK(igraph_create(graph, &edges, nbNodes, 0));
 
-    // an clear remaining things
+    /* clean remaining things */
     igraph_vector_destroy(&edges);
     IGRAPH_FINALLY_CLEAN(1);
 
-    return retval;
+    return IGRAPH_SUCCESS;
 }
 
 
@@ -4318,8 +4343,11 @@
  * graphs, at least one of k and the number of vertices must be even.
  *
  * </para><para>
- * The game simply uses \ref igraph_degree_sequence_game with appropriately
- * constructed degree sequences.
+ * Currently, this game simply uses \ref igraph_degree_sequence_game with 
+ * the \c SIMPLE_NO_MULTIPLE method and appropriately constructed degree sequences.
+ * Thefore, it does not sample uniformly: while it can generate all k-regular graphs
+ * with the given number of vertices, it does not generate each one with the same
+ * probability.
  *
  * \param graph        Pointer to an uninitialized graph object.
  * \param no_of_nodes  The number of nodes in the generated graph.
@@ -4744,7 +4772,7 @@
  * \brief Generates a random tree with the given number of nodes
  *
  * This function samples uniformly from the set of labelled trees,
- * i.e. it can generate each labelled tree with the same probability.
+ * i.e. it generates each labelled tree with the same probability.
  *
  * \param graph Pointer to an uninitialized graph object.
  * \param n The number of nodes in the tree.
@@ -4752,7 +4780,7 @@
  * \param method The algorithm to use to generate the tree. Possible values:
  *        \clist
  *        \cli IGRAPH_RANDOM_TREE_PRUFER
- *          This algorithm samples Pr&uuml;fer sequences unformly, then converts them to trees.
+ *          This algorithm samples Pr&uuml;fer sequences uniformly, then converts them to trees.
  *          Directed trees are not currently supported.
  *        \cli IGRAPH_RANDOM_LERW
  *          This algorithm effectively performs a loop-erased random walk on the complete graph
diff --git a/igraph/src/gengraph_box_list.cpp b/igraph/src/gengraph_box_list.cpp
--- a/igraph/src/gengraph_box_list.cpp
+++ b/igraph/src/gengraph_box_list.cpp
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -24,7 +24,7 @@
 namespace gengraph {
 
 void box_list::insert(int v) {
-    register int d = deg[v];
+    int d = deg[v];
     if (d < 1) {
         return;
     }
@@ -41,10 +41,10 @@
 }
 
 void box_list::pop(int v) {
-    register int p = prev[v];
-    register int n = next[v];
+    int p = prev[v];
+    int n = next[v];
     if (p < 0) {
-        register int d = deg[v];
+        int d = deg[v];
         assert(list[d - 1] == v);
         list[d - 1] = n;
         if (d == dmax && n < 0) do {
@@ -90,13 +90,13 @@
     int *w = neigh[v];
     while (k--) {
         int v2 = *(w++);
-        register int *w2 = neigh[v2];
+        int *w2 = neigh[v2];
         while (*w2 != v) {
             w2++;
         }
-        register int *w3 = neigh[v2] + (deg[v2] - 1);
+        int *w3 = neigh[v2] + (deg[v2] - 1);
         assert(w2 <= w3);
-        register int tmp = *w3;
+        int tmp = *w3;
         *w3 = *w2;
         *w2 = tmp;
         pop(v2);
diff --git a/igraph/src/gengraph_degree_sequence.cpp b/igraph/src/gengraph_degree_sequence.cpp
--- a/igraph/src/gengraph_degree_sequence.cpp
+++ b/igraph/src/gengraph_degree_sequence.cpp
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
diff --git a/igraph/src/gengraph_graph_molloy_hash.cpp b/igraph/src/gengraph_graph_molloy_hash.cpp
--- a/igraph/src/gengraph_graph_molloy_hash.cpp
+++ b/igraph/src/gengraph_graph_molloy_hash.cpp
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -132,7 +132,7 @@
     int *p = hc + 2 + n;
     int *l = links;
     for (int i = 0; i < n; i++) for (int j = HASH_SIZE(deg[i]); j--; l++) {
-            register int d;
+            int d;
             if ((d = *l) != HASH_NONE && d >= i) {
                 *(p++) = d;
             }
@@ -1168,6 +1168,6 @@
 }
 
 //___________________________________________________________________________________
-//*/
+*/
 
 } // namespace gengraph
diff --git a/igraph/src/gengraph_graph_molloy_optimized.cpp b/igraph/src/gengraph_graph_molloy_optimized.cpp
--- a/igraph/src/gengraph_graph_molloy_optimized.cpp
+++ b/igraph/src/gengraph_graph_molloy_optimized.cpp
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -34,9 +34,6 @@
 #include "igraph_statusbar.h"
 #include "igraph_progress.h"
 
-#ifndef register
-    #define register
-#endif
 
 using namespace std;
 
@@ -1051,7 +1048,7 @@
             int dv = deg[v];
             double f = target[v] / paths[v];
             // pick ALL fathers
-            register int father;
+            int father;
             for (int k = 0; k < dv; k++) if (dist[father = ww[k]] == pd) {
                     // increase target[] of father
                     target[father] += paths[father] * f;
@@ -2081,7 +2078,7 @@
 
 
 //___________________________________________________________________________________
-//*/
+*/
 
 
 
@@ -2216,6 +2213,6 @@
   return b;
 }
 
-//*/
+*/
 
 } // namespace gengraph
diff --git a/igraph/src/gengraph_mr-connected.cpp b/igraph/src/gengraph_mr-connected.cpp
--- a/igraph/src/gengraph_mr-connected.cpp
+++ b/igraph/src/gengraph_mr-connected.cpp
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -28,16 +28,18 @@
 #include "igraph_types.h"
 #include "igraph_error.h"
 
+#include "igraph_handle_exceptions.h"
+
 namespace gengraph {
 
 // return negative number if program should exit
 int parse_options(int &argc, char** &argv);
 
 // options
-static const bool MONITOR_TIME = false;
+// static const bool MONITOR_TIME = false;
 static const int  SHUFFLE_TYPE = FINAL_HEURISTICS;
-static const bool RAW_DEGREES  = false;
-static const FILE *Fdeg = stdin;
+// static const bool RAW_DEGREES  = false;
+// static const FILE *Fdeg = stdin;
 
 //_________________________________________________________________________
 // int main(int argc, char** argv) {
@@ -137,48 +139,50 @@
     int igraph_degree_sequence_game_vl(igraph_t *graph,
                                        const igraph_vector_t *out_seq,
                                        const igraph_vector_t *in_seq) {
-        long int sum = igraph_vector_sum(out_seq);
-        if (sum % 2 != 0) {
-            IGRAPH_ERROR("Sum of degrees should be even", IGRAPH_EINVAL);
-        }
+        IGRAPH_HANDLE_EXCEPTIONS(
+            long int sum = igraph_vector_sum(out_seq);
+            if (sum % 2 != 0) {
+                IGRAPH_ERROR("Sum of degrees should be even", IGRAPH_EINVAL);
+            }
 
-        RNG_BEGIN();
+            RNG_BEGIN();
 
-        if (in_seq && igraph_vector_size(in_seq) != 0) {
-            RNG_END();
-            IGRAPH_ERROR("This generator works with undirected graphs only", IGRAPH_EINVAL);
-        }
+            if (in_seq && igraph_vector_size(in_seq) != 0) {
+                RNG_END();
+                IGRAPH_ERROR("This generator works with undirected graphs only", IGRAPH_EINVAL);
+            }
 
-        degree_sequence *dd = new degree_sequence(out_seq);
+            degree_sequence *dd = new degree_sequence(out_seq);
 
-        graph_molloy_opt *g = new graph_molloy_opt(*dd);
-        delete dd;
+            graph_molloy_opt *g = new graph_molloy_opt(*dd);
+            delete dd;
 
-        if (!g->havelhakimi()) {
-            delete g;
-            RNG_END();
-            IGRAPH_ERROR("Cannot realize the given degree sequence as an undirected, simple graph",
-                         IGRAPH_EINVAL);
-        }
+            if (!g->havelhakimi()) {
+                delete g;
+                RNG_END();
+                IGRAPH_ERROR("Cannot realize the given degree sequence as an undirected, simple graph",
+                             IGRAPH_EINVAL);
+            }
 
-        if (!g->make_connected()) {
-            delete g;
-            RNG_END();
-            IGRAPH_ERROR("Cannot make a connected graph from the given degree sequence",
-                         IGRAPH_EINVAL);
-        }
+            if (!g->make_connected()) {
+                delete g;
+                RNG_END();
+                IGRAPH_ERROR("Cannot make a connected graph from the given degree sequence",
+                             IGRAPH_EINVAL);
+            }
 
-        int *hc = g->hard_copy();
-        delete g;
-        graph_molloy_hash *gh = new graph_molloy_hash(hc);
-        delete [] hc;
+            int *hc = g->hard_copy();
+            delete g;
+            graph_molloy_hash *gh = new graph_molloy_hash(hc);
+            delete [] hc;
 
-        gh->shuffle(5 * gh->nbarcs(), 100 * gh->nbarcs(), SHUFFLE_TYPE);
+            gh->shuffle(5 * gh->nbarcs(), 100 * gh->nbarcs(), SHUFFLE_TYPE);
 
-        IGRAPH_CHECK(gh->print(graph));
-        delete gh;
+            IGRAPH_CHECK(gh->print(graph));
+            delete gh;
 
-        RNG_END();
+            RNG_END();
+        );
 
         return 0;
     }
diff --git a/igraph/src/gengraph_powerlaw.cpp b/igraph/src/gengraph_powerlaw.cpp
--- a/igraph/src/gengraph_powerlaw.cpp
+++ b/igraph/src/gengraph_powerlaw.cpp
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
diff --git a/igraph/src/gengraph_random.cpp b/igraph/src/gengraph_random.cpp
--- a/igraph/src/gengraph_random.cpp
+++ b/igraph/src/gengraph_random.cpp
@@ -7,7 +7,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -28,8 +28,8 @@
 // See the header file random.h for a description of the contents of this
 // file as well as references and credits.
 
-#include <cmath>
 #include "gengraph_random.h"
+#include <cmath>
 
 using namespace std;
 using namespace KW_RNG;
diff --git a/igraph/src/glet.c b/igraph/src/glet.c
--- a/igraph/src/glet.c
+++ b/igraph/src/glet.c
@@ -75,7 +75,7 @@
     int nc;
 } igraph_i_subclique_next_free_t;
 
-void igraph_i_subclique_next_free(void *ptr) {
+static void igraph_i_subclique_next_free(void *ptr) {
     igraph_i_subclique_next_free_t *data = ptr;
     int i;
     if (data->resultids) {
@@ -123,15 +123,15 @@
  *
  */
 
-int igraph_i_subclique_next(const igraph_t *graph,
-                            const igraph_vector_t *weights,
-                            const igraph_vector_int_t *ids,
-                            const igraph_vector_ptr_t *cliques,
-                            igraph_t **result,
-                            igraph_vector_t **resultweights,
-                            igraph_vector_int_t **resultids,
-                            igraph_vector_t *clique_thr,
-                            igraph_vector_t *next_thr) {
+static int igraph_i_subclique_next(const igraph_t *graph,
+                                   const igraph_vector_t *weights,
+                                   const igraph_vector_int_t *ids,
+                                   const igraph_vector_ptr_t *cliques,
+                                   igraph_t **result,
+                                   igraph_vector_t **resultweights,
+                                   igraph_vector_int_t **resultids,
+                                   igraph_vector_t *clique_thr,
+                                   igraph_vector_t *next_thr) {
 
     /* The input is a set of cliques, that were found at a previous level.
        For each clique, we calculate the next threshold, drop the isolate
@@ -173,9 +173,9 @@
     igraph_vector_init(&newedges, 100);
     IGRAPH_FINALLY(igraph_vector_destroy, &newedges);
     igraph_vector_int_init(&mark, no_of_nodes);
-    IGRAPH_FINALLY(igraph_vector_destroy, &mark);
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &mark);
     igraph_vector_int_init(&map, no_of_nodes);
-    IGRAPH_FINALLY(igraph_vector_destroy, &map);
+    IGRAPH_FINALLY(igraph_vector_int_destroy, &map);
     igraph_vector_int_init(&edges, 100);
     IGRAPH_FINALLY(igraph_vector_int_destroy, &edges);
     igraph_vector_init(&neis, 10);
@@ -294,7 +294,7 @@
     return 0;
 }
 
-void igraph_i_graphlets_destroy_vectorlist(igraph_vector_ptr_t *vl) {
+static void igraph_i_graphlets_destroy_vectorlist(igraph_vector_ptr_t *vl) {
     int i, n = igraph_vector_ptr_size(vl);
     for (i = 0; i < n; i++) {
         igraph_vector_t *v = (igraph_vector_t*) VECTOR(*vl)[i];
@@ -305,12 +305,12 @@
     igraph_vector_ptr_destroy(vl);
 }
 
-int igraph_i_graphlets(const igraph_t *graph,
-                       const igraph_vector_t *weights,
-                       igraph_vector_ptr_t *cliques,
-                       igraph_vector_t *thresholds,
-                       const igraph_vector_int_t *ids,
-                       igraph_real_t startthr) {
+static int igraph_i_graphlets(const igraph_t *graph,
+                              const igraph_vector_t *weights,
+                              igraph_vector_ptr_t *cliques,
+                              igraph_vector_t *thresholds,
+                              const igraph_vector_int_t *ids,
+                              igraph_real_t startthr) {
 
     /* This version is different from the main function, and is
        appropriate to use in recursive calls, because it _adds_ the
@@ -401,7 +401,7 @@
     const igraph_vector_t *thresholds;
 } igraph_i_graphlets_filter_t;
 
-int igraph_i_graphlets_filter_cmp(void *data, const void *a, const void *b) {
+static int igraph_i_graphlets_filter_cmp(void *data, const void *a, const void *b) {
     igraph_i_graphlets_filter_t *ddata = (igraph_i_graphlets_filter_t *) data;
     int *aa = (int*) a;
     int *bb = (int*) b;
@@ -430,8 +430,8 @@
     }
 }
 
-int igraph_i_graphlets_filter(igraph_vector_ptr_t *cliques,
-                              igraph_vector_t *thresholds) {
+static int igraph_i_graphlets_filter(igraph_vector_ptr_t *cliques,
+                                     igraph_vector_t *thresholds) {
 
     /* Filter out non-maximal cliques. Every non-maximal clique is
        part of a maximal clique, at the same threshold.
@@ -583,6 +583,7 @@
     return 0;
 }
 
+/* TODO: not made static because it is used by the R interface */
 int igraph_i_graphlets_project(const igraph_t *graph,
                                const igraph_vector_t *weights,
                                const igraph_vector_ptr_t *cliques,
@@ -794,7 +795,7 @@
     const igraph_vector_t *Mu;
 } igraph_i_graphlets_order_t;
 
-int igraph_i_graphlets_order_cmp(void *data, const void *a, const void *b) {
+static int igraph_i_graphlets_order_cmp(void *data, const void *a, const void *b) {
     igraph_i_graphlets_order_t *ddata = (igraph_i_graphlets_order_t*) data;
     int *aa = (int*) a;
     int *bb = (int*) b;
diff --git a/igraph/src/glpk_support.c b/igraph/src/glpk_support.c
--- a/igraph/src/glpk_support.c
+++ b/igraph/src/glpk_support.c
@@ -30,7 +30,6 @@
 #include "igraph_error.h"
 #include "igraph_interrupt_internal.h"
 #include <glpk.h>
-#include <memory.h>
 #include <stdio.h>
 
 void igraph_i_glpk_interruption_hook(glp_tree *tree, void *info) {
diff --git a/igraph/src/graph.cc b/igraph/src/graph.cc
--- a/igraph/src/graph.cc
+++ b/igraph/src/graph.cc
@@ -1,4 +1,5 @@
-#include <cstdio>
+
+// #include <cstdio>
 #include <cassert>
 #include <climits>
 #include <set>
@@ -15,11 +16,6 @@
 #include <ciso646>
 #endif
 
-#ifdef USING_R
-#undef stdout
-#define stdout NULL
-#endif
-
 /*
   Copyright (c) 2003-2015 Tommi Junttila
   Released under the GNU Lesser General Public License version 3.
@@ -62,6 +58,7 @@
   first_path_automorphism = 0;
   best_path_automorphism = 0;
   in_search = false;
+  refine_equal_to_first = false;
 
   /* Default value for using "long prune" */
   opt_use_long_prune = true;
@@ -72,7 +69,7 @@
 
 
   verbose_level = 0;
-  verbstr = stdout;
+  // verbstr = stdout;
 
   report_hook = 0;
   report_user_param = 0;
@@ -115,7 +112,7 @@
 void
 AbstractGraph::set_verbose_file(FILE* const fp)
 {
-  verbstr = fp;
+  // verbstr = fp;
 }
 
 
@@ -811,6 +808,7 @@
     root.in_best_path = false;
     root.cmp_to_best_path = 0;
     root.long_prune_begin = 0;
+    root.needs_long_prune = false;
 
     root.failure_recording_ival = 0;
 
@@ -1034,15 +1032,6 @@
 		 */
 		if(index == cell->length and all_same_level == current_level+1)
 		  all_same_level = current_level;
-		if(verbstr and verbose_level >= 2) {
-		  fprintf(verbstr,
-			  "Level %u: orbits=%u, index=%u/%u, all_same_level=%u\n",
-			  current_level,
-			  first_path_orbits.nof_orbits(),
-			  index, cell->length,
-			  all_same_level);
-		  fflush(verbstr);
-		}
 	      }
 	    continue;
 	  }
@@ -2080,6 +2069,7 @@
  *-------------------------------------------------------------------------*/
 
 
+#if 0
 void
 Digraph::write_dot(const char* const filename)
 {
@@ -2116,6 +2106,7 @@
 
   fprintf(fp, "}\n");
 }
+#endif
 
 
 void
@@ -2185,6 +2176,7 @@
  *
  *-------------------------------------------------------------------------*/
 
+#if 0
 Digraph*
 Digraph::read_dimacs(FILE* const fp, FILE* const errstr)
 {
@@ -2341,11 +2333,11 @@
     delete g;
   return 0;
 }
-
-
+#endif
 
 
 
+#if 0
 void
 Digraph::write_dimacs(FILE* const fp)
 {
@@ -2387,7 +2379,7 @@
 	}
     }
 }
-
+#endif
 
 
 
@@ -3688,12 +3680,6 @@
       cr_component_elements += cell->length;
     }
 
-  if(verbstr and verbose_level > 2) {
-    fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",
-	    (long unsigned)cr_component.size(), cr_component_elements);
-    fflush(verbstr);
-  }
-
   return true;
 }
 
@@ -3889,12 +3875,6 @@
       component_elements += cell->length;
     }
 
-  if(verbstr and verbose_level > 2) {
-    fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",
-	    (long unsigned)component.size(), component_elements);
-    fflush(verbstr);
-  }
-
   return true;
 }
 
@@ -4034,6 +4014,7 @@
  *
  *-------------------------------------------------------------------------*/
 
+#if 0
 Graph*
 Graph::read_dimacs(FILE* const fp, FILE* const errstr)
 {
@@ -4249,7 +4230,7 @@
 	}
     }
 }
-
+#endif
 
 
 void
@@ -4370,6 +4351,7 @@
  *-------------------------------------------------------------------------*/
 
 
+#if 0
 void
 Graph::write_dot(const char* const filename)
 {
@@ -4407,8 +4389,7 @@
 
   fprintf(fp, "}\n");
 }
-
-
+#endif
 
 
 
@@ -5430,12 +5411,6 @@
       cr_component_elements += cell->length;
     }
 
-  if(verbstr and verbose_level > 2) {
-    fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",
-	    (long unsigned)cr_component.size(), cr_component_elements);
-    fflush(verbstr);
-  }
-
   return true;
 }
 
@@ -5593,12 +5568,6 @@
       component.push_back(cell->first);
       component_elements += cell->length;
     }
-
-  if(verbstr and verbose_level > 2) {
-    fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",
-	    (long unsigned)component.size(), component_elements);
-    fflush(verbstr);
-  }
 
   return true;
 }
diff --git a/igraph/src/gss.c b/igraph/src/gss.c
--- a/igraph/src/gss.c
+++ b/igraph/src/gss.c
@@ -4,14 +4,14 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -151,4 +151,3 @@
 
     return successful ? PLFIT_SUCCESS : PLFIT_FAILURE;
 }
-
diff --git a/igraph/src/heap.c b/igraph/src/heap.c
--- a/igraph/src/heap.c
+++ b/igraph/src/heap.c
@@ -24,10 +24,9 @@
 #include "igraph_types.h"
 #include "igraph_types_internal.h"
 #include "igraph_memory.h"
-#include "igraph_random.h"
 #include "igraph_error.h"
-#include "config.h"
 #include "igraph_math.h"
+#include "config.h"
 
 #include <assert.h>
 #include <string.h>         /* memcpy & co. */
@@ -289,12 +288,12 @@
     if (tmp1 == 0) {
         IGRAPH_ERROR("indheap reserve failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, tmp1);   /* TODO: hack */
+    IGRAPH_FINALLY(igraph_free, tmp1);
     tmp2 = igraph_Calloc(size, long int);
     if (tmp2 == 0) {
         IGRAPH_ERROR("indheap reserve failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, tmp2);
+    IGRAPH_FINALLY(igraph_free, tmp2);
     memcpy(tmp1, h->stor_begin, (size_t) actual_size * sizeof(igraph_real_t));
     memcpy(tmp2, h->index_begin, (size_t) actual_size * sizeof(long int));
     igraph_Free(h->stor_begin);
@@ -575,17 +574,17 @@
     if (tmp1 == 0) {
         IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, tmp1);   /* TODO: hack */
+    IGRAPH_FINALLY(igraph_free, tmp1);
     tmp2 = igraph_Calloc(size, long int);
     if (tmp2 == 0) {
         IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, tmp2);   /* TODO: hack */
+    IGRAPH_FINALLY(igraph_free, tmp2);
     tmp3 = igraph_Calloc(size, long int);
     if (tmp3 == 0) {
         IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, tmp3);   /* TODO: hack */
+    IGRAPH_FINALLY(igraph_free, tmp3);
 
     memcpy(tmp1, h->stor_begin, (size_t) actual_size * sizeof(igraph_real_t));
     memcpy(tmp2, h->index_begin, (size_t) actual_size * sizeof(long int));
diff --git a/igraph/src/hzeta.c b/igraph/src/hzeta.c
new file mode 100644
--- /dev/null
+++ b/igraph/src/hzeta.c
@@ -0,0 +1,651 @@
+/* vim:set ts=4 sw=2 sts=2 et: */
+
+/* This file was imported from a private scientific library
+ * based on GSL coined Home Scientific Libray (HSL) by its author
+ * Jerome Benoit; this very material is itself inspired from the
+ * material written by G. Jungan and distributed by GSL.
+ * Ultimately, some modifications were done in order to render the
+ * imported material independent from the rest of GSL.
+ */
+
+/* `hsl/specfunc/hzeta.c' C source file
+// HSL - Home Scientific Library
+// Copyright (C) 2017-2018  Jerome Benoit
+//
+// HSL is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+// The material in this file is mainly inspired by the material written by
+// G. Jungan and distributed under GPLv2 by the GNU Scientific Library (GSL)
+// ( https://www.gnu.org/software/gsl/ [specfunc/zeta.c]), itself inspired by
+// the material written by Moshier and distributed in the Cephes Mathematical
+// Library ( http://www.moshier.net/ [zeta.c]).
+//
+// More specifically, hsl_sf_hzeta_e is a slightly modifed clone of
+// gsl_sf_hzeta_e as found in GSL 2.4; the remaining is `inspired by'.
+// [Sooner or later a _Working_Note_ may be deposited at ResearchGate
+// ( https://www.researchgate.net/profile/Jerome_Benoit )]
+*/
+
+/* Author:  Jerome G. Benoit < jgmbenoit _at_ rezozer _dot_ net > */
+
+#ifdef _MSC_VER
+#define _USE_MATH_DEFINES
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include "hzeta.h"
+#include "error.h"
+#include "platform.h"
+
+/* imported from gsl_machine.h */
+
+#define GSL_LOG_DBL_MIN (-7.0839641853226408e+02)
+#define GSL_LOG_DBL_MAX 7.0978271289338397e+02
+#define GSL_DBL_EPSILON 2.2204460492503131e-16
+
+/* imported from gsl_math.h */
+
+#ifndef M_LOG2E
+#define M_LOG2E    1.44269504088896340735992468100      /* log_2 (e) */
+#endif
+
+/* imported from gsl_sf_result.h */
+
+struct gsl_sf_result_struct {
+  double val;
+  double err;
+};
+typedef struct gsl_sf_result_struct gsl_sf_result;
+
+/* imported and adapted from hsl/specfunc/specfunc_def.h */
+
+#define HSL_SF_EVAL_RESULT(FnE) \
+	gsl_sf_result result; \
+	FnE ; \
+	return (result.val);
+
+#define HSL_SF_EVAL_TUPLE_RESULT(FnET) \
+	gsl_sf_result result0; \
+	gsl_sf_result result1; \
+	FnET ; \
+	*tuple1=result1.val; \
+	*tuple0=result0.val; \
+	return (result0.val);
+
+/* */
+
+
+#define HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT 10
+#define HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER 32
+
+#define HSL_SF_LNHZETA_EULERMACLAURIN_SERIES_SHIFT_MAX 256
+
+// B_{2j}/(2j)
+static
+double hsl_sf_hzeta_eulermaclaurin_series_coeffs[HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER+1]={
+	+1.0,
+	+1.0/12.0,
+	-1.0/720.0,
+	+1.0/30240.0,
+	-1.0/1209600.0,
+	+1.0/47900160.0,
+	-691.0/1307674368000.0,
+	+1.0/74724249600.0,
+	-3.38968029632258286683019539125e-13,
+	+8.58606205627784456413590545043e-15,
+	-2.17486869855806187304151642387e-16,
+	+5.50900282836022951520265260890e-18,
+	-1.39544646858125233407076862641e-19,
+	+3.53470703962946747169322997780e-21,
+	-8.95351742703754685040261131811e-23,
+	+2.26795245233768306031095073887e-24,
+	-5.74479066887220244526388198761e-26,
+	+1.45517247561486490186626486727e-27,
+	-3.68599494066531017818178247991e-29,
+	+9.33673425709504467203255515279e-31,
+	-2.36502241570062993455963519637e-32,
+	+5.99067176248213430465991239682e-34,
+	-1.51745488446829026171081313586e-35,
+	+3.84375812545418823222944529099e-37,
+	-9.73635307264669103526762127925e-39,
+	+2.46624704420068095710640028029e-40,
+	-6.24707674182074369314875679472e-42,
+	+1.58240302446449142975108170683e-43,
+	-4.00827368594893596853001219052e-45,
+	+1.01530758555695563116307139454e-46,
+	-2.57180415824187174992481940976e-48,
+	+6.51445603523381493155843485864e-50,
+	-1.65013099068965245550609878048e-51
+	}; // hsl_sf_hzeta_eulermaclaurin_series_coeffs
+
+// 4\zeta(2j)/(2\pi)^(2j)
+static
+double hsl_sf_hzeta_eulermaclaurin_series_majorantratios[HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER+1]={
+	-2.0,
+	+1.0/6.0,
+	+1.0/360.0,
+	+1.0/15120.0,
+	+1.0/604800.0,
+	+1.0/23950080.0,
+	+691.0/653837184000.0,
+	+1.0/37362124800.0,
+	+3617.0/5335311421440000.0,
+	+1.71721241125556891282718109009e-14,
+	+4.34973739711612374608303284773e-16,
+	+1.10180056567204590304053052178e-17,
+	+2.79089293716250466814153725281e-19,
+	+7.06941407925893494338645995561e-21,
+	+1.79070348540750937008052226362e-22,
+	+4.53590490467536612062190147774e-24,
+	+1.14895813377444048905277639752e-25,
+	+2.91034495122972980373252973454e-27,
+	+7.37198988133062035636356495982e-29,
+	+1.86734685141900893440651103056e-30,
+	+4.73004483140125986911927039274e-32,
+	+1.19813435249642686093198247936e-33,
+	+3.03490976893658052342162627173e-35,
+	+7.68751625090837646445889058198e-37,
+	+1.94727061452933820705352425585e-38,
+	+4.93249408840136191421280056051e-40,
+	+1.24941534836414873862975135893e-41,
+	+3.16480604892898285950216341362e-43,
+	+8.01654737189787193706002438098e-45,
+	+2.03061517111391126232614278906e-46,
+	+5.14360831648374349984963881946e-48,
+	+1.30289120704676298631168697172e-49,
+	+3.30026198137930491101219756091e-51
+	}; // hsl_sf_hzeta_eulermaclaurin_series_majorantratios
+
+
+extern
+int hsl_sf_hzeta_e(const double s, const double q, gsl_sf_result * result) {
+
+	/* CHECK_POINTER(result) */
+
+	if ((s <= 1.0) || (q <= 0.0)) {
+		PLFIT_ERROR("s must be larger than 1.0 and q must be larger than zero", PLFIT_EINVAL);
+		}
+	else {
+		const double max_bits=54.0; // max_bits=\lceil{s}\rceil with \zeta(s,2)=\zeta(s)-1=GSL_DBL_EPSILON
+		const double ln_term0=-s*log(q);
+		if (ln_term0 < GSL_LOG_DBL_MIN+1.0) {
+			PLFIT_ERROR("underflow", PLFIT_UNDRFLOW);
+			}
+		else if (GSL_LOG_DBL_MAX-1.0 < ln_term0) {
+			PLFIT_ERROR("overflow", PLFIT_OVERFLOW);
+			}
+#if 1
+		else if (((max_bits < s) && (q < 1.0)) || ((0.5*max_bits < s) && (q < 0.25))) {
+			result->val=pow(q,-s);
+			result->err=2.0*GSL_DBL_EPSILON*fabs(result->val);
+			return (PLFIT_SUCCESS);
+			}
+		else if ((0.5*max_bits < s) && (q < 1.0)) {
+			const double a0=pow(q,-s);
+			const double p1=pow(q/(1.0+q),s);
+			const double p2=pow(q/(2.0+q),s);
+			const double ans=a0*(1.0+p1+p2);
+			result->val=ans;
+			result->err=GSL_DBL_EPSILON*(2.0+0.5*s)*fabs(result->val);
+			return (PLFIT_SUCCESS);
+			}
+#endif
+		else { // Euler-Maclaurin summation formula
+			const double qshift=HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+q;
+			const double inv_qshift=1.0/qshift;
+			const double sqr_inv_qshift=inv_qshift*inv_qshift;
+			const double inv_sm1=1.0/(s-1.0);
+			const double pmax=pow(qshift,-s);
+			double terms[HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER+1]={NAN};
+			double delta=NAN;
+			double tscp=s;
+			double scp=tscp;
+			double pcp=pmax*inv_qshift;
+			double ratio=scp*pcp;
+			size_t n=0;
+			size_t j=0;
+			double ans=0.0;
+			double mjr=NAN;
+
+			for(j=0;j<HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT;++j) ans+=(terms[n++]=pow(j+q,-s));
+			ans+=(terms[n++]=0.5*pmax);
+			ans+=(terms[n++]=pmax*qshift*inv_sm1);
+			for(j=1;j<=HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER;++j) {
+				delta=hsl_sf_hzeta_eulermaclaurin_series_coeffs[j]*ratio;
+				ans+=(terms[n++]=delta);
+				scp*=++tscp;
+				scp*=++tscp;
+				pcp*=sqr_inv_qshift;
+				ratio=scp*pcp;
+				if ((fabs(delta/ans)) < (0.5*GSL_DBL_EPSILON)) break;
+				}
+
+			ans=0.0; while (n) ans+=terms[--n];
+			mjr=hsl_sf_hzeta_eulermaclaurin_series_majorantratios[j]*ratio;
+
+			result->val=+ans;
+			result->err=2.0*((HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+1.0)*GSL_DBL_EPSILON*fabs(ans)+mjr);
+			return (PLFIT_SUCCESS);
+			}
+		}
+
+	return (PLFIT_SUCCESS); }
+
+extern
+double hsl_sf_hzeta(const double s, const double q) {
+	HSL_SF_EVAL_RESULT(hsl_sf_hzeta_e(s,q,&result)); }
+
+extern
+int hsl_sf_hzeta_deriv_e(const double s, const double q, gsl_sf_result * result) {
+
+	/* CHECK_POINTER(result) */
+
+	if ((s <= 1.0) || (q <= 0.0)) {
+		PLFIT_ERROR("s must be larger than 1.0 and q must be larger than zero", PLFIT_EINVAL);
+		}
+	else {
+		const double ln_hz_term0=-s*log(q);
+		if (ln_hz_term0 < GSL_LOG_DBL_MIN+1.0) {
+			PLFIT_ERROR("underflow", PLFIT_UNDRFLOW);
+			}
+		else if (GSL_LOG_DBL_MAX-1.0 < ln_hz_term0) {
+			PLFIT_ERROR("overflow", PLFIT_OVERFLOW);
+			}
+		else { // Euler-Maclaurin summation formula
+			const double qshift=HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+q;
+			const double inv_qshift=1.0/qshift;
+			const double sqr_inv_qshift=inv_qshift*inv_qshift;
+			const double inv_sm1=1.0/(s-1.0);
+			const double pmax=pow(qshift,-s);
+			const double lmax=log(qshift);
+			double terms[HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER+1]={NAN};
+			double delta=NAN;
+			double tscp=s;
+			double scp=tscp;
+			double pcp=pmax*inv_qshift;
+			double lcp=lmax-1.0/s;
+			double ratio=scp*pcp*lcp;
+			double qs=NAN;
+			size_t n=0;
+			size_t j=0;
+			double ans=0.0;
+			double mjr=NAN;
+
+			for(j=0,qs=q;j<HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT;++qs,++j) ans+=(terms[n++]=log(qs)*pow(qs,-s));
+			ans+=(terms[n++]=0.5*lmax*pmax);
+			ans+=(terms[n++]=pmax*qshift*inv_sm1*(lmax+inv_sm1));
+			for(j=1;j<=HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER;++j) {
+				delta=hsl_sf_hzeta_eulermaclaurin_series_coeffs[j]*ratio;
+				ans+=(terms[n++]=delta);
+				scp*=++tscp; lcp-=1.0/tscp;
+				scp*=++tscp; lcp-=1.0/tscp;
+				pcp*=sqr_inv_qshift;
+				ratio=scp*pcp*lcp;
+				if ((fabs(delta/ans)) < (0.5*GSL_DBL_EPSILON)) break;
+				}
+
+			ans=0.0; while (n) ans+=terms[--n];
+			mjr=hsl_sf_hzeta_eulermaclaurin_series_majorantratios[j]*ratio;
+
+			result->val=-ans;
+			result->err=2.0*((HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+1.0)*GSL_DBL_EPSILON*fabs(ans)+mjr);
+			return (PLFIT_SUCCESS);
+			}
+		}
+
+	return (PLFIT_SUCCESS); }
+
+extern
+double hsl_sf_hzeta_deriv(const double s, const double q) {
+	HSL_SF_EVAL_RESULT(hsl_sf_hzeta_deriv_e(s,q,&result)); }
+
+extern
+int hsl_sf_hzeta_deriv2_e(const double s, const double q, gsl_sf_result * result) {
+
+	/* CHECK_POINTER(result) */
+
+	if ((s <= 1.0) || (q <= 0.0)) {
+		PLFIT_ERROR("s must be larger than 1.0 and q must be larger than zero", PLFIT_EINVAL);
+		}
+	else {
+		const double ln_hz_term0=-s*log(q);
+		if (ln_hz_term0 < GSL_LOG_DBL_MIN+1.0) {
+			PLFIT_ERROR("underflow", PLFIT_UNDRFLOW);
+			}
+		else if (GSL_LOG_DBL_MAX-1.0 < ln_hz_term0) {
+			PLFIT_ERROR("overflow", PLFIT_OVERFLOW);
+			}
+		else { // Euler-Maclaurin summation formula
+			const double qshift=HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+q;
+			const double inv_qshift=1.0/qshift;
+			const double sqr_inv_qshift=inv_qshift*inv_qshift;
+			const double inv_sm1=1.0/(s-1.0);
+			const double pmax=pow(qshift,-s);
+			const double lmax=log(qshift);
+			const double lmax_p_inv_sm1=lmax+inv_sm1;
+			const double sqr_inv_sm1=inv_sm1*inv_sm1;
+			const double sqr_lmax=lmax*lmax;
+			const double sqr_lmax_p_inv_sm1=lmax_p_inv_sm1*lmax_p_inv_sm1;
+			double terms[HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER+1]={NAN};
+			double delta=NAN;
+			double tscp=s;
+			double slcp=NAN;
+			double plcp=NAN;
+			double scp=tscp;
+			double pcp=pmax*inv_qshift;
+			double lcp=1.0/s-lmax;
+			double sqr_lcp=lmax*(lmax-2.0/s);
+			double ratio=scp*pcp*sqr_lcp;
+			double qs=NAN;
+			double lqs=NAN;
+			size_t n=0;
+			size_t j=0;
+			double ans=0.0;
+			double mjr=NAN;
+
+			for(j=0,qs=q;j<HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT;++qs,++j) {
+				lqs=log(qs);
+				ans+=(terms[n++]=lqs*lqs*pow(qs,-s));
+				}
+			ans+=(terms[n++]=0.5*sqr_lmax*pmax);
+			ans+=(terms[n++]=pmax*qshift*inv_sm1*(sqr_lmax_p_inv_sm1+sqr_inv_sm1));
+			for(j=1;j<=HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER;++j) {
+				delta=hsl_sf_hzeta_eulermaclaurin_series_coeffs[j]*ratio;
+				ans+=(terms[n++]=delta);
+				scp*=++tscp; slcp=plcp=1.0/tscp;
+				scp*=++tscp; slcp+=1.0/tscp; plcp/=tscp;
+				pcp*=sqr_inv_qshift;
+				sqr_lcp+=2.0*(plcp+slcp*lcp);
+				ratio=scp*pcp*sqr_lcp;
+				if ((fabs(delta/ans)) < (0.5*GSL_DBL_EPSILON)) break;
+				lcp+=slcp;
+				}
+
+			ans=0.0; while (n) ans+=terms[--n];
+			mjr=hsl_sf_hzeta_eulermaclaurin_series_majorantratios[j]*ratio;
+
+			result->val=+ans;
+			result->err=2.0*((HSL_SF_HZETA_EULERMACLAURIN_SERIES_SHIFT+1.0)*GSL_DBL_EPSILON*fabs(ans)+mjr);
+			return (PLFIT_SUCCESS);
+			}
+		}
+
+	return (PLFIT_SUCCESS); }
+
+extern
+double hsl_sf_hzeta_deriv2(const double s, const double q) {
+	HSL_SF_EVAL_RESULT(hsl_sf_hzeta_deriv2_e(s,q,&result)); }
+
+static inline
+double hsl_sf_hZeta0_zed(const double s, const double q) {
+#if 1
+	const long double ld_q=(long double)(q);
+	const long double ld_s=(long double)(s);
+	const long double ld_log1prq=log1pl(1.0L/ld_q);
+	const long double ld_epsilon=expm1l(-ld_s*ld_log1prq);
+	const long double ld_z=ld_s+(ld_q+0.5L*ld_s+0.5L)*ld_epsilon;
+	const double z=(double)(ld_z);
+#else
+	double z=s+(q+0.5*s+0.5)*expm1(-s*log1p(1.0/q));
+#endif
+	return (z); }
+
+// Z_{0}(s,a) = a^s \left(\frac{1}{2}+\frac{a}{s-1}\right)^{-1} \zeta(s,a) - 1
+// Z_{0}(s,a) = O\left(\frac{(s-1)s}{6a^{2}}\right)
+static
+int hsl_sf_hZeta0(const double s, const double q, double * value, double * abserror) {
+	const double criterion=ceil(10.0*s-q);
+	const size_t shift=(criterion<0.0)?0:
+		(criterion<HSL_SF_LNHZETA_EULERMACLAURIN_SERIES_SHIFT_MAX)?(size_t)(llrint(criterion)):
+			HSL_SF_LNHZETA_EULERMACLAURIN_SERIES_SHIFT_MAX;
+	const double qshift=(double)(shift)+q;
+	const double inv_qshift=1.0/qshift;
+	const double sqr_inv_qshift=inv_qshift*inv_qshift;
+	const double sm1=s-1.0;
+	double terms[HSL_SF_LNHZETA_EULERMACLAURIN_SERIES_SHIFT_MAX+HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER+1]={NAN};
+	double delta=NAN;
+	double tscp=s;
+	double scp=s*sm1;
+	double pcp=inv_qshift/(2.0*qshift+sm1);
+	double ratio=NAN;
+	size_t n=0;
+	size_t j=0;
+	double ans=0.0;
+	double mjr=NAN;
+
+	if (shift) {
+		const double hsm1=0.5*sm1;
+		const double inv_q=1.0/q;
+		const double qphsm1=q+hsm1;
+		const double inv_qphsm1=1.0/qphsm1;
+		const double qshiftphsm1=qshift+hsm1;
+		double qs=q;
+		double a=1.0;
+		for(j=0;j<shift;) {
+			ans+=(terms[n++]=a*hsl_sf_hZeta0_zed(s,qs++)*inv_qphsm1);
+			a=exp(-s*log1p((++j)*inv_q));
+			}
+		pcp*=a*qshiftphsm1*inv_qphsm1;
+		}
+	ratio=scp*pcp;
+	ans+=terms[n++]=ratio/6.0;
+	scp*=++tscp;
+	scp*=++tscp;
+	pcp*=2.0*sqr_inv_qshift;
+	ratio=scp*pcp;
+	for(j=2;j<=HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER;++j) {
+		delta=hsl_sf_hzeta_eulermaclaurin_series_coeffs[j]*ratio;
+		ans+=(terms[n++]=delta);
+		scp*=++tscp;
+		scp*=++tscp;
+		pcp*=sqr_inv_qshift;
+		ratio=scp*pcp;
+		if ((fabs(delta/ans)) < (0.5*GSL_DBL_EPSILON)) break;
+		}
+
+	ans=0.0; while (n) ans+=terms[--n];
+	mjr=hsl_sf_hzeta_eulermaclaurin_series_majorantratios[j]*ratio;
+
+	*value=ans;
+	*abserror=2.0*((shift+1)*GSL_DBL_EPSILON*fabs(ans)+mjr);
+
+	return (PLFIT_SUCCESS); }
+
+static inline
+double hsl_sf_hZeta1_zed(const double s, const double q) {
+#if 1
+	const long double ld_q=(long double)(q);
+	const long double ld_s=(long double)(s);
+	const long double ld_sm1=ld_s-1.0L;
+	const long double ld_logq=logl(ld_q);
+	const long double ld_log1prq=log1pl(1.0L/ld_q);
+	const long double ld_inv_logq=1.0L/ld_logq;
+	const long double ld_logratiom1=ld_log1prq*ld_inv_logq;
+	const long double ld_powratiom1=expm1l(-ld_s*ld_log1prq);
+	const long double ld_varepsilon=expm1l(-ld_sm1*ld_log1prq);
+	const long double ld_epsilon=ld_logratiom1+ld_powratiom1+ld_logratiom1*ld_powratiom1;
+	const long double ld_z=ld_s+(ld_q+0.5L*ld_s+0.5L)*ld_epsilon+ld_q/ld_sm1*ld_inv_logq*ld_varepsilon;
+	const double z=(double)(ld_z);
+#else
+	const double sm1=s-1.0;
+	const double inv_ln_q=1.0/log(q);
+	const double log1prq=log1p(1.0/q);
+	const double logratiom1=log1prq*inv_ln_q;
+	const double powratiom1=expm1(-s*log1prq);
+	const double epsilon=logratiom1+powratiom1+logratiom1*powratiom1;
+	const double z=s+(q+0.5*s+0.5)*epsilon+q/sm1*inv_ln_q*expm1(-sm1*log1prq);
+#endif
+	return (z); }
+
+// Z_{1}(s,a) = -\frac{a^s}{\ln(a)} \left(\frac{1}{2}+\frac{a}{s-1}\,\left[1+\frac{1}{(s-1)\,\ln(a)}\right]\right)^{-1} \zeta^{\prime}(s,a) - 1
+// Z_{1}(s,a) = O\left(\frac{(s-1)s}{6a^{2}}\right)
+static
+int hsl_sf_hZeta1(const double s, const double q, const double ln_q, double * value, double * abserror, double * coeff1) {
+	const double criterion=ceil(10.0*s-q);
+	const size_t shift=(criterion<0.0)?0:
+		(criterion<HSL_SF_LNHZETA_EULERMACLAURIN_SERIES_SHIFT_MAX)?(size_t)(llrint(criterion)):
+			HSL_SF_LNHZETA_EULERMACLAURIN_SERIES_SHIFT_MAX;
+	const double qshift=(double)(shift)+q;
+	const double ln_qshift=log(qshift);
+	const double inv_qshift=1.0/qshift;
+	const double inv_ln_q=1.0/ln_q;
+	const double inv_ln_qshift=1.0/ln_qshift;
+	const double sqr_inv_qshift=inv_qshift*inv_qshift;
+	const double sm1=s-1.0;
+	const double hsm1=0.5*sm1;
+	const double q_over_ln_q=q*inv_ln_q;
+	const double qshift_over_ln_qshift=qshift*inv_ln_qshift;
+	const double qphsm1=q+hsm1;
+	const double qshiftphsm1=qshift+hsm1;
+	double terms[HSL_SF_LNHZETA_EULERMACLAURIN_SERIES_SHIFT_MAX+HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER+1]={NAN};
+	double delta=NAN;
+	double tscp=s;
+	double scp=s*sm1;
+	double pcp=inv_qshift*sm1/(qshift_over_ln_qshift+sm1*qshiftphsm1);
+	double lcp=1.0-inv_ln_qshift/s;
+	double ratio=NAN;
+	size_t n=0;
+	size_t j=0;
+	double ans=0.0;
+	double mjr=NAN;
+
+	if (shift) {
+		const double inv_q=1.0/q;
+		const double inv_sm1=1.0/sm1;
+		const double w=1.0+inv_sm1*inv_ln_q;
+		const double wshift=1.0+inv_sm1*inv_ln_qshift;
+		const double qwphsm1=q*w+hsm1;
+		const double inv_qwphsm1=1.0/qwphsm1;
+		const double qshiftwshiftphsm1=qshift*wshift+hsm1;
+		double qs=q;
+		double a=1.0;
+		for(j=0;j<shift;) {
+			ans+=(terms[n++]=a*hsl_sf_hZeta1_zed(s,qs++)*inv_qwphsm1);
+			a=log(qs)*inv_ln_q*exp(-s*log1p((++j)*inv_q));
+			}
+		pcp*=a*qshiftwshiftphsm1*inv_qwphsm1;
+		}
+	ratio=scp*pcp*lcp;
+	ans+=terms[n++]=ratio/12.0;
+	scp*=++tscp; lcp-=inv_ln_qshift/tscp;
+	scp*=++tscp; lcp-=inv_ln_qshift/tscp;
+	pcp*=sqr_inv_qshift;
+	ratio=scp*pcp*lcp;
+	for(j=2;j<=HSL_SF_HZETA_EULERMACLAURIN_SERIES_ORDER;++j) {
+		delta=hsl_sf_hzeta_eulermaclaurin_series_coeffs[j]*ratio;
+		ans+=(terms[n++]=delta);
+		scp*=++tscp; lcp-=inv_ln_qshift/tscp;
+		scp*=++tscp; lcp-=inv_ln_qshift/tscp;
+		pcp*=sqr_inv_qshift;
+		ratio=scp*pcp*lcp;
+		if ((fabs(delta/ans)) < (0.5*GSL_DBL_EPSILON)) break;
+		}
+
+	ans=0.0; while (n) ans+=terms[--n];
+	mjr=hsl_sf_hzeta_eulermaclaurin_series_majorantratios[j]*ratio;
+
+	*value=ans;
+	*abserror=2.0*((shift+1)*GSL_DBL_EPSILON*fabs(ans)+mjr);
+
+	if (coeff1) *coeff1=1.0+q_over_ln_q/qphsm1/sm1;
+
+	return (PLFIT_SUCCESS); }
+
+extern
+int hsl_sf_lnhzeta_deriv_tuple_e(const double s, const double q, gsl_sf_result * result, gsl_sf_result * result_deriv) {
+
+	/* CHECK_POINTER(result) */
+
+	if ((s <= 1.0) || (q <= 0.0)) {
+		PLFIT_ERROR("s must be larger than 1.0 and q must be larger than zero", PLFIT_EINVAL);
+		}
+	else if (q == 1.0) {
+		const double inv_sm1=1.0/(s-1.0);
+		const double inv_qsm1=4.0*inv_sm1;
+		const double hz_coeff0=exp2(s+1.0);
+		const double hz_coeff1=1.0+inv_qsm1;
+		double hZeta0_value=NAN;
+		double hZeta0_abserror=NAN;
+		hsl_sf_hZeta0(s,2.0,&hZeta0_value,&hZeta0_abserror);
+		hZeta0_value+=1.0;
+		if (result) {
+			const double ln_hz_coeff=hz_coeff1/hz_coeff0;
+			const double ln_hZeta0_value=ln_hz_coeff*hZeta0_value;
+			result->val=log1p(ln_hZeta0_value);
+			result->err=(2.0*GSL_DBL_EPSILON*ln_hz_coeff+hZeta0_abserror)/(1.0+ln_hZeta0_value);
+			}
+
+		if (result_deriv) {
+			const double ld_hz_coeff2=1.0+inv_sm1*M_LOG2E;
+			const double ld_hz_coeff1=1.0+inv_qsm1*ld_hz_coeff2;
+			double hZeta1_value=NAN;
+			double hZeta1_abserror=NAN;
+			hsl_sf_hZeta1(s,2.0,M_LN2,&hZeta1_value,&hZeta1_abserror,NULL);
+			hZeta0_value*=hz_coeff1;
+			hZeta0_value+=hz_coeff0;
+			hZeta1_value+=1.0;
+			hZeta1_value*=-M_LN2*ld_hz_coeff1;
+			result_deriv->val=hZeta1_value/hZeta0_value;
+			result_deriv->err=2.0*GSL_DBL_EPSILON*fabs(result_deriv->val)+(hZeta0_abserror+hZeta1_abserror);
+			}
+		}
+	else {
+		const double ln_q=log(q);
+		double hZeta0_value=NAN;
+		double hZeta0_abserror=NAN;
+		hsl_sf_hZeta0(s,q,&hZeta0_value,&hZeta0_abserror);
+		if (result) {
+			const double ln_hz_term0=-s*ln_q;
+			const double ln_hz_term1=log(0.5+q/(s-1.0));
+			result->val=ln_hz_term0+ln_hz_term1+log1p(hZeta0_value);
+			result->err=2.0*GSL_DBL_EPSILON*(fabs(ln_hz_term0)+fabs(ln_hz_term1))+hZeta0_abserror/(1.0+hZeta0_value);
+			}
+		if (result_deriv) {
+			double hZeta1_value=NAN;
+			double hZeta1_abserror=NAN;
+			double ld_hz_coeff1=NAN;
+			hsl_sf_hZeta1(s,q,ln_q,&hZeta1_value,&hZeta1_abserror,&ld_hz_coeff1);
+			result_deriv->val=-ln_q*ld_hz_coeff1*(1.0+hZeta1_value)/(1.0+hZeta0_value);
+			result_deriv->err=2.0*GSL_DBL_EPSILON*fabs(result_deriv->val)+(hZeta0_abserror+hZeta1_abserror);
+			}
+		}
+
+	return (PLFIT_SUCCESS); }
+
+extern
+double hsl_sf_lnhzeta_deriv_tuple(const double s, const double q, double * tuple0, double * tuple1) {
+	HSL_SF_EVAL_TUPLE_RESULT(hsl_sf_lnhzeta_deriv_tuple_e(s,q,&result0,&result1)); }
+
+extern
+int hsl_sf_lnhzeta_e(const double s, const double q, gsl_sf_result * result) {
+	return (hsl_sf_lnhzeta_deriv_tuple_e(s,q,result,NULL)); }
+
+extern
+double hsl_sf_lnhzeta(const double s, const double q) {
+	HSL_SF_EVAL_RESULT(hsl_sf_lnhzeta_e(s,q,&result)); }
+
+extern
+int hsl_sf_lnhzeta_deriv_e(const double s, const double q, gsl_sf_result * result) {
+	return (hsl_sf_lnhzeta_deriv_tuple_e(s,q,NULL,result)); }
+
+extern
+double hsl_sf_lnhzeta_deriv(const double s, const double q) {
+	HSL_SF_EVAL_RESULT(hsl_sf_lnhzeta_deriv_e(s,q,&result)); }
+
+//
+// End of file `hsl/specfunc/hzeta.c'.
diff --git a/igraph/src/igraph_fixed_vectorlist.c b/igraph/src/igraph_fixed_vectorlist.c
--- a/igraph/src/igraph_fixed_vectorlist.c
+++ b/igraph/src/igraph_fixed_vectorlist.c
@@ -50,7 +50,7 @@
     }
     IGRAPH_FINALLY(igraph_free, l->vecs);
     IGRAPH_CHECK(igraph_vector_ptr_init(&l->v, size));
-    IGRAPH_FINALLY(igraph_fixed_vectorlist_destroy, &l->v);
+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &l->v);
     IGRAPH_VECTOR_INIT_FINALLY(&sizes, size);
 
     for (i = 0; i < no; i++) {
diff --git a/igraph/src/igraph_hashtable.c b/igraph/src/igraph_hashtable.c
--- a/igraph/src/igraph_hashtable.c
+++ b/igraph/src/igraph_hashtable.c
@@ -32,7 +32,7 @@
     IGRAPH_CHECK(igraph_trie_init(&ht->keys, 1));
     IGRAPH_FINALLY(igraph_trie_destroy, &ht->keys);
     IGRAPH_CHECK(igraph_strvector_init(&ht->elements, 0));
-    IGRAPH_FINALLY(igraph_trie_destroy, &ht->elements);
+    IGRAPH_FINALLY(igraph_strvector_destroy, &ht->elements);
     IGRAPH_CHECK(igraph_strvector_init(&ht->defaults, 0));
 
     IGRAPH_FINALLY_CLEAN(2);
@@ -87,7 +87,7 @@
     if (tmp == 0) {
         IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, tmp);
+    IGRAPH_FINALLY(igraph_free, tmp);
     strncpy(tmp, elem, elemlen);
     tmp[elemlen] = '\0';
 
diff --git a/igraph/src/igraph_hrg.cc b/igraph/src/igraph_hrg.cc
--- a/igraph/src/igraph_hrg.cc
+++ b/igraph/src/igraph_hrg.cc
@@ -82,7 +82,7 @@
 };
 }
 
-int markovChainMonteCarlo(dendro *d, unsigned int period,
+static int markovChainMonteCarlo(dendro *d, unsigned int period,
                           igraph_hrg_t *hrg) {
 
     igraph_real_t bestL = d->getLikelihood();
@@ -121,7 +121,7 @@
     return 0;
 }
 
-int markovChainMonteCarlo2(dendro *d, int num_samples) {
+static int markovChainMonteCarlo2(dendro *d, int num_samples) {
     bool flag_taken;
     double dL, ptest = 1.0 / (50.0 * (double)(d->g->numNodes()));
     int sample_num = 0, t = 1, thresh = 200 * d->g->numNodes();
@@ -150,7 +150,7 @@
     return 0;
 }
 
-int MCMCEquilibrium_Find(dendro *d, igraph_hrg_t *hrg) {
+static int MCMCEquilibrium_Find(dendro *d, igraph_hrg_t *hrg) {
 
     // We want to run the MCMC until we've found equilibrium; we
     // use the heuristic of the average log-likelihood (which is
@@ -187,8 +187,8 @@
     return 0;
 }
 
-int igraph_i_hrg_getgraph(const igraph_t *igraph,
-                          dendro *d) {
+static int igraph_i_hrg_getgraph(const igraph_t *igraph,
+                                 dendro *d) {
 
     int no_of_nodes = igraph_vcount(igraph);
     int no_of_edges = igraph_ecount(igraph);
@@ -217,9 +217,9 @@
     return 0;
 }
 
-int igraph_i_hrg_getsimplegraph(const igraph_t *igraph,
-                                dendro *d, simpleGraph **sg,
-                                int num_bins) {
+static int igraph_i_hrg_getsimplegraph(const igraph_t *igraph,
+                                       dendro *d, simpleGraph **sg,
+                                       int num_bins) {
 
     int no_of_nodes = igraph_vcount(igraph);
     int no_of_edges = igraph_ecount(igraph);
@@ -448,7 +448,7 @@
 int igraph_hrg_sample(const igraph_t *input_graph,
                       igraph_t *sample,
                       igraph_vector_ptr_t *samples,
-                      int no_samples,
+                      igraph_integer_t no_samples,
                       igraph_hrg_t *hrg,
                       igraph_bool_t start) {
 
@@ -693,7 +693,7 @@
     return 0;
 }
 
-int MCMCEquilibrium_Sample(dendro *d, int num_samples) {
+static int MCMCEquilibrium_Sample(dendro *d, int num_samples) {
 
     // Because moves in the dendrogram space are chosen (Monte
     // Carlo) so that we sample dendrograms with probability
@@ -725,7 +725,7 @@
     return 0;
 }
 
-int QsortPartition (pblock* array, int left, int right, int index) {
+static int QsortPartition (pblock* array, int left, int right, int index) {
     pblock p_value, temp;
     p_value.L = array[index].L;
     p_value.i = array[index].i;
@@ -772,7 +772,7 @@
     return stored;
 }
 
-void QsortMain (pblock* array, int left, int right) {
+static void QsortMain (pblock* array, int left, int right) {
     if (right > left) {
         int pivot = left;
         int part  = QsortPartition(array, left, right, pivot);
@@ -782,7 +782,7 @@
     return;
 }
 
-int rankCandidatesByProbability(simpleGraph *sg, dendro *d,
+static int rankCandidatesByProbability(simpleGraph *sg, dendro *d,
                                 pblock *br_list, int mk) {
     int mkk = 0;
     int n = sg->getNumNodes();
@@ -804,7 +804,7 @@
     return 0;
 }
 
-int recordPredictions(pblock *br_list, igraph_vector_t *edges,
+static int recordPredictions(pblock *br_list, igraph_vector_t *edges,
                       igraph_vector_t *prob, int mk) {
 
     IGRAPH_CHECK(igraph_vector_resize(edges, mk * 2));
diff --git a/igraph/src/igraph_hrg_types.cc b/igraph/src/igraph_hrg_types.cc
--- a/igraph/src/igraph_hrg_types.cc
+++ b/igraph/src/igraph_hrg_types.cc
@@ -41,6 +41,7 @@
 #include "igraph_constructors.h"
 #include "igraph_random.h"
 
+using namespace std;
 using namespace fitHRG;
 
 // ******** Red-Black Tree Methods ***************************************
diff --git a/igraph/src/igraph_psumtree.c b/igraph/src/igraph_psumtree.c
--- a/igraph/src/igraph_psumtree.c
+++ b/igraph/src/igraph_psumtree.c
@@ -31,7 +31,7 @@
 #include <math.h>
 #include <stdio.h>
 
-double igraph_i_log2(double f) {
+static double igraph_i_log2(double f) {
     return log(f) / log(2.0);
 }
 
diff --git a/igraph/src/igraph_strvector.c b/igraph/src/igraph_strvector.c
--- a/igraph/src/igraph_strvector.c
+++ b/igraph/src/igraph_strvector.c
@@ -24,7 +24,6 @@
 #include "igraph_types.h"
 #include "igraph_strvector.h"
 #include "igraph_memory.h"
-#include "igraph_random.h"
 #include "igraph_error.h"
 #include "config.h"
 
diff --git a/igraph/src/igraph_trie.c b/igraph/src/igraph_trie.c
--- a/igraph/src/igraph_trie.c
+++ b/igraph/src/igraph_trie.c
@@ -39,7 +39,7 @@
  *         igraph_vector_ptr_init() and igraph_vector_init() might be returned.
  */
 
-int igraph_i_trie_init_node(igraph_trie_node_t *t) {
+static int igraph_i_trie_init_node(igraph_trie_node_t *t) {
     IGRAPH_STRVECTOR_INIT_FINALLY(&t->strs, 0);
     IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->children, 0);
     IGRAPH_VECTOR_INIT_FINALLY(&t->values, 0);
@@ -47,7 +47,7 @@
     return 0;
 }
 
-void igraph_i_trie_destroy_node(igraph_trie_node_t *t, igraph_bool_t sfree);
+static void igraph_i_trie_destroy_node(igraph_trie_node_t *t);
 
 /**
  * \ingroup igraphtrie
@@ -59,8 +59,8 @@
 int igraph_trie_init(igraph_trie_t *t, igraph_bool_t storekeys) {
     t->maxvalue = -1;
     t->storekeys = storekeys;
-    IGRAPH_CHECK(igraph_i_trie_init_node( (igraph_trie_node_t *)t ));
-    IGRAPH_FINALLY(igraph_i_trie_destroy_node, t);
+    IGRAPH_CHECK(igraph_i_trie_init_node( (igraph_trie_node_t *) t ));
+    IGRAPH_FINALLY(igraph_i_trie_destroy_node, (igraph_trie_node_t *) t );
     if (storekeys) {
         IGRAPH_CHECK(igraph_strvector_init(&t->keys, 0));
     }
@@ -74,13 +74,13 @@
  * \brief Destroys a node of a trie (not to be called directly).
  */
 
-void igraph_i_trie_destroy_node(igraph_trie_node_t *t, igraph_bool_t sfree) {
+static void igraph_i_trie_destroy_node_helper(igraph_trie_node_t *t, igraph_bool_t sfree) {
     long int i;
     igraph_strvector_destroy(&t->strs);
     for (i = 0; i < igraph_vector_ptr_size(&t->children); i++) {
         igraph_trie_node_t *child = VECTOR(t->children)[i];
         if (child != 0) {
-            igraph_i_trie_destroy_node(child, 1);
+            igraph_i_trie_destroy_node_helper(child, 1);
         }
     }
     igraph_vector_ptr_destroy(&t->children);
@@ -90,6 +90,10 @@
     }
 }
 
+static void igraph_i_trie_destroy_node(igraph_trie_node_t *t) {
+    igraph_i_trie_destroy_node_helper(t, 0);
+}
+
 /**
  * \ingroup igraphtrie
  * \brief Destroys a trie (frees allocated memory).
@@ -99,7 +103,7 @@
     if (t->storekeys) {
         igraph_strvector_destroy(&t->keys);
     }
-    igraph_i_trie_destroy_node( (igraph_trie_node_t*) t, 0);
+    igraph_i_trie_destroy_node( (igraph_trie_node_t*) t);
 }
 
 
@@ -108,7 +112,7 @@
  * \brief Internal helping function for igraph_trie_t
  */
 
-long int igraph_i_strdiff(const char *str, const char *key) {
+static long int igraph_i_strdiff(const char *str, const char *key) {
 
     long int diff = 0;
     while (key[diff] != '\0' && str[diff] != '\0' && str[diff] == key[diff]) {
@@ -210,9 +214,9 @@
                 IGRAPH_ERROR("cannot add to trie", IGRAPH_ENOMEM);
             }
             str2[diff] = '\0';
-            IGRAPH_FINALLY(free, str2);
+            IGRAPH_FINALLY(igraph_free, str2);
             IGRAPH_CHECK(igraph_strvector_set(&t->strs, i, str2));
-            free(str2);
+            igraph_Free(str2);
             IGRAPH_FINALLY_CLEAN(4);
 
             VECTOR(t->values)[i] = newvalue;
@@ -246,9 +250,9 @@
                 IGRAPH_ERROR("cannot add to trie", IGRAPH_ENOMEM);
             }
             str2[diff] = '\0';
-            IGRAPH_FINALLY(free, str2);
+            IGRAPH_FINALLY(igraph_free, str2);
             IGRAPH_CHECK(igraph_strvector_set(&t->strs, i, str2));
-            free(str2);
+            igraph_Free(str2);
             IGRAPH_FINALLY_CLEAN(4);
 
             VECTOR(t->values)[i] = -1;
@@ -345,7 +349,7 @@
 
     strncpy(tmp, key, length);
     tmp[length] = '\0';
-    IGRAPH_FINALLY(free, tmp);
+    IGRAPH_FINALLY(igraph_free, tmp);
     IGRAPH_CHECK(igraph_trie_get(t, tmp, id));
     igraph_Free(tmp);
     IGRAPH_FINALLY_CLEAN(1);
diff --git a/igraph/src/infomap.cc b/igraph/src/infomap.cc
--- a/igraph/src/infomap.cc
+++ b/igraph/src/infomap.cc
@@ -318,5 +318,8 @@
 
     delete fgraph;
     IGRAPH_FINALLY_CLEAN(1);
+
+	IGRAPH_CHECK(igraph_reindex_membership(membership, 0, 0));
+
     return IGRAPH_SUCCESS;
 }
diff --git a/igraph/src/infomap_FlowGraph.cc b/igraph/src/infomap_FlowGraph.cc
--- a/igraph/src/infomap_FlowGraph.cc
+++ b/igraph/src/infomap_FlowGraph.cc
@@ -26,6 +26,8 @@
 
 #define plogp( x ) ( (x) > 0.0 ? (x)*log(x) : 0.0 )
 
+using namespace std;
+
 void FlowGraph::init(int n, const igraph_vector_t *v_weights) {
     alpha = 0.15;
     beta  = 1.0 - alpha;
diff --git a/igraph/src/infomap_Greedy.cc b/igraph/src/infomap_Greedy.cc
--- a/igraph/src/infomap_Greedy.cc
+++ b/igraph/src/infomap_Greedy.cc
@@ -26,6 +26,8 @@
 #include <iterator>
 #define plogp( x ) ( (x) > 0.0 ? (x)*log(x) : 0.0 )
 
+using namespace std;
+
 Greedy::Greedy(FlowGraph * fgraph) {
     graph = fgraph;
     Nnode = graph->Nnode;
diff --git a/igraph/src/infomap_Node.cc b/igraph/src/infomap_Node.cc
--- a/igraph/src/infomap_Node.cc
+++ b/igraph/src/infomap_Node.cc
@@ -24,6 +24,8 @@
 
 #include "infomap_Node.h"
 
+using namespace std;
+
 Node::Node() {
     exit = 0.0;
     size = 0.0;
diff --git a/igraph/src/interrupt.c b/igraph/src/interrupt.c
--- a/igraph/src/interrupt.c
+++ b/igraph/src/interrupt.c
@@ -24,10 +24,6 @@
 #include "igraph_interrupt.h"
 #include "config.h"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
 IGRAPH_THREAD_LOCAL igraph_interruption_handler_t
 *igraph_i_interruption_handler = 0;
 
diff --git a/igraph/src/iterators.c b/igraph/src/iterators.c
--- a/igraph/src/iterators.c
+++ b/igraph/src/iterators.c
@@ -23,7 +23,6 @@
 
 #include "igraph_iterators.h"
 #include "igraph_memory.h"
-#include "igraph_random.h"
 #include "igraph_interface.h"
 #include "config.h"
 
@@ -878,7 +877,7 @@
  * \function igraph_ess_all
  * \brief Edge set, all edges (immediate version)
  *
- * The immediate version of the all-vertices selector.
+ * The immediate version of the all-edges selector.
  *
  * \param order Constant giving the order of the edges in the edge
  *        selector. See \ref igraph_es_all() for the possible values.
@@ -1430,12 +1429,12 @@
     return es->type;
 }
 
-int igraph_i_es_pairs_size(const igraph_t *graph,
-                           const igraph_es_t *es, igraph_integer_t *result);
-int igraph_i_es_path_size(const igraph_t *graph,
-                          const igraph_es_t *es, igraph_integer_t *result);
-int igraph_i_es_multipairs_size(const igraph_t *graph,
-                                const igraph_es_t *es, igraph_integer_t *result);
+static int igraph_i_es_pairs_size(const igraph_t *graph,
+                                  const igraph_es_t *es, igraph_integer_t *result);
+static int igraph_i_es_path_size(const igraph_t *graph,
+                                 const igraph_es_t *es, igraph_integer_t *result);
+static int igraph_i_es_multipairs_size(const igraph_t *graph,
+                                       const igraph_es_t *es, igraph_integer_t *result);
 
 /**
  * \function igraph_es_size
@@ -1514,8 +1513,8 @@
     return 0;
 }
 
-int igraph_i_es_pairs_size(const igraph_t *graph,
-                           const igraph_es_t *es, igraph_integer_t *result) {
+static int igraph_i_es_pairs_size(const igraph_t *graph,
+                                  const igraph_es_t *es, igraph_integer_t *result) {
     long int n = igraph_vector_size(es->data.path.ptr);
     long int no_of_nodes = igraph_vcount(graph);
     long int i;
@@ -1542,8 +1541,8 @@
     return 0;
 }
 
-int igraph_i_es_path_size(const igraph_t *graph,
-                          const igraph_es_t *es, igraph_integer_t *result) {
+static int igraph_i_es_path_size(const igraph_t *graph,
+                                 const igraph_es_t *es, igraph_integer_t *result) {
     long int n = igraph_vector_size(es->data.path.ptr);
     long int no_of_nodes = igraph_vcount(graph);
     long int i;
@@ -1569,27 +1568,27 @@
     return 0;
 }
 
-int igraph_i_es_multipairs_size(const igraph_t *graph,
-                                const igraph_es_t *es, igraph_integer_t *result) {
+static int igraph_i_es_multipairs_size(const igraph_t *graph,
+                                       const igraph_es_t *es, igraph_integer_t *result) {
     IGRAPH_UNUSED(graph); IGRAPH_UNUSED(es); IGRAPH_UNUSED(result);
     IGRAPH_ERROR("Cannot calculate edge selector length", IGRAPH_UNIMPLEMENTED);
 }
 
 /**************************************************/
 
-int igraph_i_eit_create_allfromto(const igraph_t *graph,
-                                  igraph_eit_t *eit,
-                                  igraph_neimode_t mode);
-int igraph_i_eit_pairs(const igraph_t *graph,
-                       igraph_es_t es, igraph_eit_t *eit);
-int igraph_i_eit_multipairs(const igraph_t *graph,
-                            igraph_es_t es, igraph_eit_t *eit);
-int igraph_i_eit_path(const igraph_t *graph,
-                      igraph_es_t es, igraph_eit_t *eit);
+static int igraph_i_eit_create_allfromto(const igraph_t *graph,
+                                         igraph_eit_t *eit,
+                                         igraph_neimode_t mode);
+static int igraph_i_eit_pairs(const igraph_t *graph,
+                              igraph_es_t es, igraph_eit_t *eit);
+static int igraph_i_eit_multipairs(const igraph_t *graph,
+                                   igraph_es_t es, igraph_eit_t *eit);
+static int igraph_i_eit_path(const igraph_t *graph,
+                             igraph_es_t es, igraph_eit_t *eit);
 
-int igraph_i_eit_create_allfromto(const igraph_t *graph,
-                                  igraph_eit_t *eit,
-                                  igraph_neimode_t mode) {
+static int igraph_i_eit_create_allfromto(const igraph_t *graph,
+                                         igraph_eit_t *eit,
+                                         igraph_neimode_t mode) {
     igraph_vector_t *vec;
     long int no_of_nodes = igraph_vcount(graph);
     long int i;
@@ -1647,8 +1646,8 @@
     return 0;
 }
 
-int igraph_i_eit_pairs(const igraph_t *graph,
-                       igraph_es_t es, igraph_eit_t *eit) {
+static int igraph_i_eit_pairs(const igraph_t *graph,
+                              igraph_es_t es, igraph_eit_t *eit) {
     long int n = igraph_vector_size(es.data.path.ptr);
     long int no_of_nodes = igraph_vcount(graph);
     long int i;
@@ -1686,8 +1685,8 @@
     return 0;
 }
 
-int igraph_i_eit_multipairs(const igraph_t *graph,
-                            igraph_es_t es, igraph_eit_t *eit) {
+static int igraph_i_eit_multipairs(const igraph_t *graph,
+                                   igraph_es_t es, igraph_eit_t *eit) {
     long int n = igraph_vector_size(es.data.path.ptr);
     long int no_of_nodes = igraph_vcount(graph);
 
@@ -1718,8 +1717,8 @@
     return 0;
 }
 
-int igraph_i_eit_path(const igraph_t *graph,
-                      igraph_es_t es, igraph_eit_t *eit) {
+static int igraph_i_eit_path(const igraph_t *graph,
+                             igraph_es_t es, igraph_eit_t *eit) {
     long int n = igraph_vector_size(es.data.path.ptr);
     long int no_of_nodes = igraph_vcount(graph);
     long int i, len;
diff --git a/igraph/src/kolmogorov.c b/igraph/src/kolmogorov.c
--- a/igraph/src/kolmogorov.c
+++ b/igraph/src/kolmogorov.c
@@ -4,14 +4,14 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/igraph/src/lad.c b/igraph/src/lad.c
--- a/igraph/src/lad.c
+++ b/igraph/src/lad.c
@@ -46,13 +46,7 @@
    -- Tamas Nepusz, 11 July 2013
 */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-#include <limits.h>
-
+#include "igraph_topology.h"
 #include "igraph_interface.h"
 #include "igraph_adjlist.h"
 #include "igraph_vector.h"
@@ -61,6 +55,12 @@
 #include "igraph_matrix.h"
 #include "igraph_interrupt_internal.h"
 
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+
+
 /* define boolean type as char */
 #define true 1
 #define false 0
@@ -99,7 +99,7 @@
     igraph_matrix_char_t isEdge;
 } Tgraph;
 
-int igraph_i_lad_createGraph(const igraph_t *igraph, Tgraph* graph) {
+static int igraph_i_lad_createGraph(const igraph_t *igraph, Tgraph* graph) {
     long int i, j, n;
     long int no_of_nodes = igraph_vcount(igraph);
     igraph_vector_int_t *neis;
@@ -112,8 +112,7 @@
 
     IGRAPH_CHECK(igraph_adjlist_init(igraph, &graph->succ, IGRAPH_OUT));
     IGRAPH_FINALLY(igraph_adjlist_destroy, &graph->succ);
-    IGRAPH_CHECK(igraph_matrix_char_init(&graph->isEdge,
-                                         no_of_nodes, no_of_nodes));
+    IGRAPH_CHECK(igraph_matrix_char_init(&graph->isEdge, no_of_nodes, no_of_nodes));
     IGRAPH_FINALLY(igraph_matrix_char_destroy, &graph->isEdge);
 
     for (i = 0; i < no_of_nodes; i++) {
@@ -129,9 +128,18 @@
         }
     }
 
-    return 0;
+    IGRAPH_FINALLY_CLEAN(3);
+
+    return IGRAPH_SUCCESS;
 }
 
+static void igraph_i_lad_destroyGraph(Tgraph *graph) {
+    igraph_matrix_char_destroy(&graph->isEdge);
+    igraph_adjlist_destroy(&graph->succ);
+    igraph_vector_destroy(&graph->nbSucc);
+}
+
+
 /* ---------------------------------------------------------*/
 /* Coming from domains.c                                    */
 /* ---------------------------------------------------------*/
@@ -169,19 +177,19 @@
        or -1 if v is not matched */
 } Tdomain;
 
-bool igraph_i_lad_toFilterEmpty(Tdomain* D) {
+static bool igraph_i_lad_toFilterEmpty(Tdomain* D) {
     /* return true if there is no more nodes in toFilter */
     return (D->nextOutToFilter < 0);
 }
 
-void igraph_i_lad_resetToFilter(Tdomain *D) {
+static void igraph_i_lad_resetToFilter(Tdomain *D) {
     /* empty to filter and unmark the vertices that are marked to be filtered */
     igraph_vector_char_null(&D->markedToFilter);
     D->nextOutToFilter = -1;
 }
 
 
-int igraph_i_lad_nextToFilter(Tdomain* D, int size) {
+static int igraph_i_lad_nextToFilter(Tdomain* D, int size) {
     /* precondition: emptyToFilter = false
        remove a node from toFilter (FIFO)
        unmark this node and return it */
@@ -198,7 +206,7 @@
     return u;
 }
 
-void igraph_i_lad_addToFilter(int u, Tdomain* D, int size) {
+static void igraph_i_lad_addToFilter(int u, Tdomain* D, int size) {
     /* if u is not marked, then add it to toFilter and mark it */
     if (VECTOR(D->markedToFilter)[u]) {
         return;
@@ -215,13 +223,13 @@
     VECTOR(D->toFilter)[D->lastInToFilter] = u;
 }
 
-bool igraph_i_lad_isInD(int u, int v, Tdomain* D) {
+static bool igraph_i_lad_isInD(int u, int v, Tdomain* D) {
     /* returns true if v belongs to D(u); false otherwise */
     return (MATRIX(D->posInVal, u, v) <
             VECTOR(D->firstVal)[u] + VECTOR(D->nbVal)[u]);
 }
 
-int igraph_i_lad_augmentingPath(int u, Tdomain* D, int nbV, bool* result) {
+static int igraph_i_lad_augmentingPath(int u, Tdomain* D, int nbV, bool* result) {
     /* return true if there exists an augmenting path starting from u and
        ending on a free vertex v in the bipartite directed graph G=(U,
        V, E) such that U=pattern nodes, V=target nodes, and
@@ -289,7 +297,7 @@
     return 0;
 }
 
-int igraph_i_lad_removeAllValuesButOne(int u, int v, Tdomain* D, Tgraph* Gp,
+static int igraph_i_lad_removeAllValuesButOne(int u, int v, Tdomain* D, Tgraph* Gp,
                                        Tgraph* Gt, bool* result) {
     /* remove all values but v from D(u) and add all successors of u in
        toFilter return false if an inconsistency is detected wrt to
@@ -323,7 +331,7 @@
 }
 
 
-int igraph_i_lad_removeValue(int u, int v, Tdomain* D, Tgraph* Gp,
+static int igraph_i_lad_removeValue(int u, int v, Tdomain* D, Tgraph* Gp,
                              Tgraph* Gt, bool* result) {
     /* remove v from D(u) and add all successors of u in toFilter
        return false if an inconsistency is detected wrt global all diff */
@@ -358,7 +366,7 @@
 }
 
 
-int igraph_i_lad_matchVertices(int nb, igraph_vector_int_t* toBeMatched,
+static int igraph_i_lad_matchVertices(int nb, igraph_vector_int_t* toBeMatched,
                                bool induced, Tdomain* D, Tgraph* Gp,
                                Tgraph* Gt, int *invalid) {
     /* for each u in toBeMatched[0..nb-1], match u to
@@ -439,7 +447,7 @@
 }
 
 
-bool igraph_i_lad_matchVertex(int u, bool induced, Tdomain* D, Tgraph* Gp,
+static bool igraph_i_lad_matchVertex(int u, bool induced, Tdomain* D, Tgraph* Gp,
                               Tgraph *Gt) {
     int invalid;
     /* match u to D->val[D->firstVal[u]] and filter domains of other non
@@ -461,13 +469,13 @@
 }
 
 
-int igraph_i_lad_qcompare (void const *a, void const *b) {
+static int igraph_i_lad_qcompare (void const *a, void const *b) {
     /* function used by the qsort function */
     int pa = *((int*)a) - *((int*)b);
     return pa;
 }
 
-bool igraph_i_lad_compare(int size_mu, int* mu, int size_mv, int* mv) {
+static bool igraph_i_lad_compare(int size_mu, int* mu, int size_mv, int* mv) {
     /* return true if for every element u of mu there exists
        a different element v of mv such that u <= v;
        return false otherwise */
@@ -484,9 +492,9 @@
     return true;
 }
 
-int igraph_i_lad_initDomains(bool initialDomains,
-                             igraph_vector_ptr_t *domains, Tdomain* D,
-                             Tgraph* Gp, Tgraph* Gt, int *empty) {
+static int igraph_i_lad_initDomains(bool initialDomains,
+                                    const igraph_vector_ptr_t *domains, Tdomain *D,
+                                    const Tgraph *Gp, const Tgraph *Gt, int *empty) {
     /* for every pattern node u, initialize D(u) with every vertex v
        such that for every neighbor u' of u there exists a different
        neighbor v' of v such that degree(u) <= degree(v)
@@ -498,8 +506,6 @@
     int *mu, *mv;
     int matchingSize, u, v, i, j;
     igraph_vector_t *vec;
-    igraph_vector_t *Gp_uneis;
-    igraph_vector_t *Gt_vneis;
 
     val = igraph_Calloc(Gp->nbVertices * Gt->nbVertices, int);
     if (val == 0) {
@@ -512,16 +518,13 @@
         IGRAPH_ERROR("cannot allocated 'dom' array in igraph_i_lad_initDomains", IGRAPH_ENOMEM);
     }
 
-    IGRAPH_CHECK(igraph_vector_int_init(&D->globalMatchingP, Gp->nbVertices));
-    IGRAPH_FINALLY(igraph_vector_int_destroy, &D->globalMatchingP);
+    IGRAPH_VECTOR_INT_INIT_FINALLY(&D->globalMatchingP, Gp->nbVertices);
     igraph_vector_int_fill(&D->globalMatchingP, -1L);
 
-    IGRAPH_CHECK(igraph_vector_int_init(&D->globalMatchingT, Gt->nbVertices));
-    IGRAPH_FINALLY(igraph_vector_int_destroy, &D->globalMatchingT);
+    IGRAPH_VECTOR_INT_INIT_FINALLY(&D->globalMatchingT, Gt->nbVertices);
     igraph_vector_int_fill(&D->globalMatchingT, -1L);
 
-    IGRAPH_CHECK(igraph_vector_int_init(&D->nbVal, Gp->nbVertices));
-    IGRAPH_FINALLY(igraph_vector_int_destroy, &D->nbVal);
+    IGRAPH_VECTOR_INT_INIT_FINALLY(&D->nbVal, Gp->nbVertices);
 
     IGRAPH_CHECK(igraph_vector_int_init(&D->firstVal, Gp->nbVertices));
     IGRAPH_FINALLY(igraph_vector_int_destroy, &D->firstVal);
@@ -537,8 +540,7 @@
     IGRAPH_CHECK(igraph_vector_char_init(&D->markedToFilter, Gp->nbVertices));
     IGRAPH_FINALLY(igraph_vector_char_destroy, &D->markedToFilter);
 
-    IGRAPH_CHECK(igraph_vector_int_init(&D->toFilter, Gp->nbVertices));
-    IGRAPH_FINALLY(igraph_vector_int_destroy, &D->toFilter);
+    IGRAPH_VECTOR_INT_INIT_FINALLY(&D->toFilter, Gp->nbVertices);
 
     D->valSize = 0;
     matchingSize = 0;
@@ -603,30 +605,55 @@
         }
         if (VECTOR(D->nbVal)[u] == 0) {
             *empty = 1;  /* empty domain */
+
             igraph_free(val);
             igraph_free(dom);
-            return 0;
+
+            /* On this branch, 'val' and 'matching' are unused.
+             * We init them anyway so that we can have a consistent destructor. */
+            IGRAPH_VECTOR_INT_INIT_FINALLY(&D->val, 0);
+            IGRAPH_VECTOR_INT_INIT_FINALLY(&D->matching, 0);
+            IGRAPH_FINALLY_CLEAN(10);
+
+            return IGRAPH_SUCCESS;
         }
     }
-    IGRAPH_CHECK(igraph_vector_int_init(&D->val, D->valSize));
-    IGRAPH_FINALLY(igraph_vector_int_destroy, &D->val);
+    IGRAPH_VECTOR_INT_INIT_FINALLY(&D->val, D->valSize);
     for (i = 0; i < D->valSize; i++) {
         VECTOR(D->val)[i] = val[i];
     }
 
-    IGRAPH_CHECK(igraph_vector_int_init(&D->matching, matchingSize));
-    IGRAPH_FINALLY(igraph_vector_int_destroy, &D->matching);
+    IGRAPH_VECTOR_INT_INIT_FINALLY(&D->matching, matchingSize);
     igraph_vector_int_fill(&D->matching, -1);
 
     D->nextOutToFilter = 0;
     D->lastInToFilter = (int) (Gp->nbVertices - 1);
+
     *empty = 0;
 
     igraph_free(val);
     igraph_free(dom);
-    return 0;
+
+    IGRAPH_FINALLY_CLEAN(10);
+
+    return IGRAPH_SUCCESS;
 }
 
+static void igraph_i_lad_destroyDomains(Tdomain *D) {
+    igraph_vector_int_destroy(&D->globalMatchingP);
+    igraph_vector_int_destroy(&D->globalMatchingT);
+    igraph_vector_int_destroy(&D->nbVal);
+    igraph_vector_int_destroy(&D->firstVal);
+    igraph_matrix_int_destroy(&D->posInVal);
+    igraph_matrix_int_destroy(&D->firstMatch);
+    igraph_vector_char_destroy(&D->markedToFilter);
+    igraph_vector_int_destroy(&D->toFilter);
+
+    igraph_vector_int_destroy(&D->val);
+    igraph_vector_int_destroy(&D->matching);
+}
+
+
 /* ---------------------------------------------------------*/
 /* Coming from allDiff.c                                    */
 /* ---------------------------------------------------------*/
@@ -637,14 +664,14 @@
 #define toBeDeleted 3
 #define deleted 4
 
-void igraph_i_lad_addToDelete(int u, int* list, int* nb, int* marked) {
+static void igraph_i_lad_addToDelete(int u, int* list, int* nb, int* marked) {
     if (marked[u] < toBeDeleted) {
         list[(*nb)++] = u;
         marked[u] = toBeDeleted;
     }
 }
 
-int igraph_i_lad_updateMatching(int sizeOfU, int sizeOfV,
+static int igraph_i_lad_updateMatching(int sizeOfU, int sizeOfV,
                                 igraph_vector_int_t *degree,
                                 igraph_vector_int_t *firstAdj,
                                 igraph_vector_int_t *adj,
@@ -897,7 +924,7 @@
     return 0;
 }
 
-void igraph_i_lad_DFS(int nbU, int nbV, int u, bool* marked, int* nbSucc,
+static void igraph_i_lad_DFS(int nbU, int nbV, int u, bool* marked, int* nbSucc,
                       int* succ, igraph_vector_int_t * matchedWithU,
                       int* order, int* nb) {
     /* perform a depth first search, starting from u, in the bipartite
@@ -925,7 +952,7 @@
     order[*nb] = u; (*nb)--;
 }
 
-int igraph_i_lad_SCC(int nbU, int nbV, int* numV, int* numU,
+static int igraph_i_lad_SCC(int nbU, int nbV, int* numV, int* numU,
                      int* nbSucc, int* succ,
                      int* nbPred, int* pred,
                      igraph_vector_int_t * matchedWithU,
@@ -1000,7 +1027,7 @@
 }
 
 
-int igraph_i_lad_ensureGACallDiff(bool induced, Tgraph* Gp, Tgraph* Gt,
+static int igraph_i_lad_ensureGACallDiff(bool induced, Tgraph* Gp, Tgraph* Gt,
                                   Tdomain* D, int *invalid) {
     /* precondition: D->globalMatchingP is an all different matching of
        the pattern vertices
@@ -1127,7 +1154,7 @@
 /* Coming from lad.c                                        */
 /* ---------------------------------------------------------*/
 
-int igraph_i_lad_checkLAD(int u, int v, Tdomain* D, Tgraph* Gp, Tgraph* Gt,
+static int igraph_i_lad_checkLAD(int u, int v, Tdomain* D, Tgraph* Gp, Tgraph* Gt,
                           bool *result) {
     /* return true if G_(u, v) has a adj(u)-covering matching; false
        otherwise */
@@ -1278,7 +1305,7 @@
 /* Coming from main.c                                      */
 /* ---------------------------------------------------------*/
 
-int igraph_i_lad_filter(bool induced, Tdomain* D, Tgraph* Gp, Tgraph* Gt,
+static int igraph_i_lad_filter(bool induced, Tdomain* D, Tgraph* Gp, Tgraph* Gt,
                         bool *result) {
     /* filter domains of all vertices in D->toFilter wrt LAD and ensure
        GAC(allDiff)
@@ -1327,7 +1354,7 @@
 
 
 
-int igraph_i_lad_solve(int timeLimit, bool firstSol, bool induced,
+static int igraph_i_lad_solve(int timeLimit, bool firstSol, bool induced,
                        Tdomain* D, Tgraph* Gp, Tgraph* Gt,
                        int *invalid, igraph_bool_t *iso,
                        igraph_vector_t *map, igraph_vector_ptr_t *maps,
@@ -1575,14 +1602,18 @@
     }
 
     IGRAPH_CHECK(igraph_i_lad_createGraph(pattern, &Gp));
+    IGRAPH_FINALLY(igraph_i_lad_destroyGraph, &Gp);
+
     IGRAPH_CHECK(igraph_i_lad_createGraph(target, &Gt));
+    IGRAPH_FINALLY(igraph_i_lad_destroyGraph, &Gt);
 
     if (Gp.nbVertices > Gt.nbVertices) {
         goto exit3;
     }
 
-    IGRAPH_CHECK(igraph_i_lad_initDomains(initialDomains, domains, &D, &Gp,
-                                          &Gt, &invalidDomain));
+    IGRAPH_CHECK(igraph_i_lad_initDomains(initialDomains, domains, &D, &Gp, &Gt, &invalidDomain));
+    IGRAPH_FINALLY(igraph_i_lad_destroyDomains, &D);
+
     if (invalidDomain) {
         goto exit2;
     }
@@ -1634,32 +1665,16 @@
     IGRAPH_FINALLY_CLEAN(1);
 
 exit:
-
-    igraph_vector_int_destroy(&D.val);
-    igraph_vector_int_destroy(&D.matching);
-    IGRAPH_FINALLY_CLEAN(2);
-
 exit2:
 
-    igraph_vector_int_destroy(&D.globalMatchingP);
-    igraph_vector_int_destroy(&D.globalMatchingT);
-    igraph_vector_int_destroy(&D.nbVal);
-    igraph_vector_int_destroy(&D.firstVal);
-    igraph_matrix_int_destroy(&D.posInVal);
-    igraph_matrix_int_destroy(&D.firstMatch);
-    igraph_vector_char_destroy(&D.markedToFilter);
-    igraph_vector_int_destroy(&D.toFilter);
-    IGRAPH_FINALLY_CLEAN(8);
+    igraph_i_lad_destroyDomains(&D);
+    IGRAPH_FINALLY_CLEAN(1);
 
 exit3:
 
-    igraph_matrix_char_destroy(&Gt.isEdge);
-    igraph_adjlist_destroy(&Gt.succ);
-    igraph_vector_destroy(&Gt.nbSucc);
-    igraph_matrix_char_destroy(&Gp.isEdge);
-    igraph_adjlist_destroy(&Gp.succ);
-    igraph_vector_destroy(&Gp.nbSucc);
-    IGRAPH_FINALLY_CLEAN(6);
+    igraph_i_lad_destroyGraph(&Gt);
+    igraph_i_lad_destroyGraph(&Gp);
+    IGRAPH_FINALLY_CLEAN(2);
 
     return 0;
 }
diff --git a/igraph/src/lapack.c b/igraph/src/lapack.c
--- a/igraph/src/lapack.c
+++ b/igraph/src/lapack.c
@@ -21,6 +21,7 @@
 
 */
 
+#include "igraph_blas.h"
 #include "igraph_lapack.h"
 #include "igraph_lapack_internal.h"
 
@@ -615,7 +616,7 @@
  *
  * </para><para>
  * Optionally also, it computes a balancing transformation to improve
- * the conditioning of the eigenvalues and eigenvectors (\p ilo, \pihi,
+ * the conditioning of the eigenvalues and eigenvectors (\p ilo, \p ihi,
  * \p scale, and \p abnrm), reciprocal condition numbers for the
  * eigenvalues (\p rconde), and reciprocal condition numbers for the
  * right eigenvectors (\p rcondv).
@@ -625,8 +626,8 @@
  *                   A * v(j) = lambda(j) * v(j)
  * where lambda(j) is its eigenvalue.
  * The left eigenvector u(j) of A satisfies
- *               u(j)**H * A = lambda(j) * u(j)**H
- * where u(j)**H denotes the conjugate transpose of u(j).
+ *               u(j)^H * A = lambda(j) * u(j)^H
+ * where u(j)^H denotes the conjugate transpose of u(j).
  *
  * </para><para>
  * The computed eigenvectors are normalized to have Euclidean norm
@@ -635,7 +636,7 @@
  * </para><para>
  * Balancing a matrix means permuting the rows and columns to make it
  * more nearly upper triangular, and applying a diagonal similarity
- * transformation D * A * D**(-1), where D is a diagonal matrix, to
+ * transformation D * A * D^(-1), where D is a diagonal matrix, to
  * make its rows and columns closer in norm and the condition numbers
  * of its eigenvalues and eigenvectors smaller.  The computed
  * reciprocal condition numbers correspond to the balanced matrix.
@@ -654,7 +655,7 @@
  *          triangular. Do not diagonally scale.
  *     \cli IGRAPH_LAPACK_DGEEVX_BALANCE_SCALE
  *          diagonally scale the matrix, i.e. replace A by
- *          D*A*D**(-1), where D is a diagonal matrix, chosen to make
+ *          D*A*D^(-1), where D is a diagonal matrix, chosen to make
  *          the rows and columns of A more equal in norm. Do not
  *          permute.
  *     \cli IGRAPH_LAPACK_DGEEVX_BALANCE_BOTH
@@ -683,7 +684,7 @@
  *   J=1,...,ilo-1 or I=ihi+1,...,N.
  * \param scale Pointer to an initialized vector or a NULL pointer. If
  *   not a NULL pointer, then details of the permutations and scaling
- *   factors applied when balancing \param A, are stored here.
+ *   factors applied when balancing \p A, are stored here.
  *   If P(j) is the index of the row and column
  *   interchanged with row and column j, and D(j) is the scaling
  *   factor applied to row and column j, then
@@ -938,17 +939,10 @@
 
 int igraph_lapack_ddot(const igraph_vector_t *v1, const igraph_vector_t *v2,
                        igraph_real_t *res) {
-
-    int n = igraph_vector_size(v1);
-    int one = 1;
-
-    if (igraph_vector_size(v2) != n) {
-        IGRAPH_ERROR("Dot product of vectors with different dimensions",
-                     IGRAPH_EINVAL);
-    }
-
-    *res = igraphddot_(&n, VECTOR(*v1), &one, VECTOR(*v2), &one);
-
-    return 0;
+    IGRAPH_WARNING(
+        "igraph_lapack_ddot() is a misnomer; use igraph_blas_ddot() instead. "
+        "igraph_lapack_ddot() will be removed in igraph 0.9.0."
+    );
+    return igraph_blas_ddot(v1, v2, res);
 }
 
diff --git a/igraph/src/layout.c b/igraph/src/layout.c
--- a/igraph/src/layout.c
+++ b/igraph/src/layout.c
@@ -44,7 +44,6 @@
 #include "config.h"
 #include <math.h>
 #include "igraph_math.h"
-#include <stdio.h> /* FIXME */
 
 
 /**
@@ -380,9 +379,7 @@
     return 0;
 }
 
-void igraph_i_norm2d(igraph_real_t *x, igraph_real_t *y);
-
-void igraph_i_norm2d(igraph_real_t *x, igraph_real_t *y) {
+static void igraph_i_norm2d(igraph_real_t *x, igraph_real_t *y) {
     igraph_real_t len = sqrt((*x) * (*x) + (*y) * (*y));
     if (len != 0) {
         *x /= len;
@@ -696,13 +693,7 @@
 
 }
 
-int igraph_i_layout_reingold_tilford_unreachable(
-    const igraph_t *graph,
-    igraph_neimode_t mode,
-    long int real_root,
-    long int no_of_nodes,
-    igraph_vector_t *pnewedges);
-int igraph_i_layout_reingold_tilford_unreachable(
+static int igraph_i_layout_reingold_tilford_unreachable(
     const igraph_t *graph,
     igraph_neimode_t mode,
     long int real_root,
@@ -782,24 +773,27 @@
               of the subtree rooted at this node */
     long int right_contour; /* Next right node of the contour
               of the subtree rooted at this node */
-    igraph_real_t offset_follow_lc;  /* X offset when following the left contour */
-    igraph_real_t offset_follow_rc;  /* X offset when following the right contour */
+    igraph_real_t offset_to_left_contour;  /* X offset when following the left contour */
+    igraph_real_t offset_to_right_contour;  /* X offset when following the right contour */
+    long int left_extreme;  /* Leftmost node on the deepest layer of the subtree rooted at this node */
+    long int right_extreme; /* Rightmost node on the deepest layer of the subtree rooted at this node */
+    igraph_real_t offset_to_left_extreme;  /* X offset when jumping to the left extreme node */
+    igraph_real_t offset_to_right_extreme;  /* X offset when jumping to the right extreme node */
 };
 
-int igraph_i_layout_reingold_tilford_postorder(struct igraph_i_reingold_tilford_vertex *vdata,
-        long int node, long int vcount);
-int igraph_i_layout_reingold_tilford_calc_coords(struct igraph_i_reingold_tilford_vertex *vdata,
-        igraph_matrix_t *res, long int node,
-        long int vcount, igraph_real_t xpos);
+static int igraph_i_layout_reingold_tilford_postorder(struct igraph_i_reingold_tilford_vertex *vdata,
+                                                      long int node, long int vcount);
+static int igraph_i_layout_reingold_tilford_calc_coords(struct igraph_i_reingold_tilford_vertex *vdata,
+                                                        igraph_matrix_t *res, long int node,
+                                                        long int vcount, igraph_real_t xpos);
 
-int igraph_i_layout_reingold_tilford(const igraph_t *graph,
-                                     igraph_matrix_t *res,
-                                     igraph_neimode_t mode,
-                                     long int root);
-int igraph_i_layout_reingold_tilford(const igraph_t *graph,
-                                     igraph_matrix_t *res,
-                                     igraph_neimode_t mode,
-                                     long int root) {
+/* uncomment the next line for debugging the Reingold-Tilford layout */
+/* #define LAYOUT_RT_DEBUG 1 */
+
+static int igraph_i_layout_reingold_tilford(const igraph_t *graph,
+                                            igraph_matrix_t *res,
+                                            igraph_neimode_t mode,
+                                            long int root) {
     long int no_of_nodes = igraph_vcount(graph);
     long int i, n, j;
     igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;
@@ -825,8 +819,12 @@
         vdata[i].offset = 0.0;
         vdata[i].left_contour = -1;
         vdata[i].right_contour = -1;
-        vdata[i].offset_follow_lc = 0.0;
-        vdata[i].offset_follow_rc = 0.0;
+        vdata[i].offset_to_left_contour = 0.0;
+        vdata[i].offset_to_right_contour = 0.0;
+        vdata[i].left_extreme = i;
+        vdata[i].right_extreme = i;
+        vdata[i].offset_to_left_extreme = 0.0;
+        vdata[i].offset_to_right_extreme = 0.0;
     }
     vdata[root].parent = root;
     vdata[root].level = 0;
@@ -868,10 +866,29 @@
 
     IGRAPH_PROGRESS("Reingold-Tilford tree layout", 100.0, NULL);
 
+#ifdef LAYOUT_RT_DEBUG
+    for (i = 0; i < no_of_nodes; i++) {
+        printf(
+            "%3ld: offset = %.2f, contours = [%ld, %ld], contour offsets = [%.2f, %.2f]\n",
+            i, vdata[i].offset,
+            vdata[i].left_contour, vdata[i].right_contour,
+            vdata[i].offset_to_left_contour, vdata[i].offset_to_right_contour
+        );
+        if (vdata[i].left_extreme != i || vdata[i].right_extreme != i) {
+            printf(
+                "     extrema = [%ld, %ld], offsets to extrema = [%.2f, %.2f]\n",
+                vdata[i].left_extreme, vdata[i].right_extreme,
+                vdata[i].offset_to_left_extreme, vdata[i].offset_to_right_extreme
+            );
+        }
+    }
+#endif
+
     return 0;
 }
 
-int igraph_i_layout_reingold_tilford_calc_coords(struct igraph_i_reingold_tilford_vertex *vdata,
+static int igraph_i_layout_reingold_tilford_calc_coords(
+        struct igraph_i_reingold_tilford_vertex *vdata,
         igraph_matrix_t *res, long int node,
         long int vcount, igraph_real_t xpos) {
     long int i;
@@ -888,12 +905,16 @@
     return 0;
 }
 
-int igraph_i_layout_reingold_tilford_postorder(struct igraph_i_reingold_tilford_vertex *vdata,
+static int igraph_i_layout_reingold_tilford_postorder(
+        struct igraph_i_reingold_tilford_vertex *vdata,
         long int node, long int vcount) {
     long int i, j, childcount, leftroot, leftrootidx;
+    const igraph_real_t minsep = 1;
     igraph_real_t avg;
 
-    /* printf("Starting visiting node %d\n", node); */
+#ifdef LAYOUT_RT_DEBUG
+    printf("Starting visiting node %ld\n", node);
+#endif
 
     /* Check whether this node is a leaf node */
     childcount = 0;
@@ -922,93 +943,156 @@
      * will be checked against the left contour of the next subtree */
     leftroot = leftrootidx = -1;
     avg = 0.0;
-    /*printf("Visited node %d and arranged its subtrees\n", node);*/
+#ifdef LAYOUT_RT_DEBUG
+    printf("Visited node %ld and arranged its subtrees\n", node);
+#endif
     for (i = 0, j = 0; i < vcount; i++) {
         if (i == node) {
             continue;
         }
         if (vdata[i].parent == node) {
-            /*printf("  Placing child %d on level %d\n", i, vdata[i].level);*/
             if (leftroot >= 0) {
                 /* Now we will follow the right contour of leftroot and the
                  * left contour of the subtree rooted at i */
-                long lnode, rnode;
-                igraph_real_t loffset, roffset, minsep, rootsep;
+                long lnode, rnode, auxnode;
+                igraph_real_t loffset, roffset, rootsep, newoffset;
+
+#ifdef LAYOUT_RT_DEBUG
+                printf("  Placing child %ld on level %ld, to the right of %ld\n", i, vdata[i].level, leftroot);
+#endif
                 lnode = leftroot; rnode = i;
-                minsep = 1;
                 rootsep = vdata[leftroot].offset + minsep;
-                loffset = 0; roffset = minsep;
-                /*printf("    Contour: [%d, %d], offsets: [%lf, %lf], rootsep: %lf\n",
-                       lnode, rnode, loffset, roffset, rootsep);*/
+                loffset = vdata[leftroot].offset; roffset = loffset + minsep;
+
+                /* Keep on updating the right contour now that we have attached
+                 * a new node to the subtree being built */
+                vdata[node].right_contour = i;
+                vdata[node].offset_to_right_contour = rootsep;
+
+#ifdef LAYOUT_RT_DEBUG
+                printf("    Contour: [%ld, %ld], offsets: [%lf, %lf], rootsep: %lf\n",
+                       lnode, rnode, loffset, roffset, rootsep);
+#endif
                 while ((lnode >= 0) && (rnode >= 0)) {
                     /* Step to the next level on the right contour of the left subtree */
                     if (vdata[lnode].right_contour >= 0) {
-                        loffset += vdata[lnode].offset_follow_rc;
+                        loffset += vdata[lnode].offset_to_right_contour;
                         lnode = vdata[lnode].right_contour;
                     } else {
-                        /* Left subtree ended there. The right contour of the left subtree
-                         * will continue to the next step on the right subtree. */
+                        /* Left subtree ended there. The left and right contour
+                         * of the left subtree will continue to the next step
+                         * on the right subtree. */
                         if (vdata[rnode].left_contour >= 0) {
-                            /*printf("      Left subtree ended, continuing left subtree's left and right contour on right subtree (node %ld)\n", vdata[rnode].left_contour);*/
-                            vdata[lnode].left_contour = vdata[rnode].left_contour;
-                            vdata[lnode].right_contour = vdata[rnode].left_contour;
-                            vdata[lnode].offset_follow_lc = vdata[lnode].offset_follow_rc =
-                                                                (roffset - loffset) + vdata[rnode].offset_follow_lc;
-                            /*printf("      vdata[lnode].offset_follow_* = %.4f\n", vdata[lnode].offset_follow_lc);*/
+                            auxnode = vdata[node].left_extreme;
+
+                            /* this is the "threading" step that the original
+                             * paper is talking about */
+                            newoffset = (vdata[node].offset_to_right_extreme - vdata[node].offset_to_left_extreme) + minsep + vdata[rnode].offset_to_left_contour;
+                            vdata[auxnode].left_contour = vdata[rnode].left_contour;
+                            vdata[auxnode].right_contour = vdata[rnode].left_contour;
+                            vdata[auxnode].offset_to_left_contour = vdata[auxnode].offset_to_right_contour = newoffset;
+
+                            /* since we attached a larger subtree to the
+                             * already placed left subtree, we need to update
+                             * the extrema of the subtree rooted at 'node' */
+                            vdata[node].left_extreme = vdata[i].left_extreme;
+                            vdata[node].right_extreme = vdata[i].right_extreme;
+                            vdata[node].offset_to_left_extreme = vdata[i].offset_to_left_extreme + rootsep;
+                            vdata[node].offset_to_right_extreme = vdata[i].offset_to_right_extreme + rootsep;
+#ifdef LAYOUT_RT_DEBUG
+                            printf("      Left subtree ended earlier, continuing left subtree's left and right contour on right subtree (node %ld gets connected to node %ld)\n", auxnode, vdata[rnode].left_contour);
+                            printf("      New contour following offset for node %ld is %lf\n", auxnode, vdata[auxnode].offset_to_left_contour);
+#endif
+                        } else {
+                            /* Both subtrees are ending at the same time; the
+                             * left extreme node of the subtree rooted at
+                             * 'node' remains the same but the right extreme
+                             * will change */
+                            vdata[node].right_extreme = vdata[i].right_extreme;
+                            vdata[node].offset_to_right_extreme = vdata[i].offset_to_right_extreme + rootsep;
                         }
                         lnode = -1;
                     }
                     /* Step to the next level on the left contour of the right subtree */
                     if (vdata[rnode].left_contour >= 0) {
-                        roffset += vdata[rnode].offset_follow_lc;
+                        roffset += vdata[rnode].offset_to_left_contour;
                         rnode = vdata[rnode].left_contour;
                     } else {
-                        /* Right subtree ended here. The left contour of the right
+                        /* Right subtree ended here. The right contour of the right
                          * subtree will continue to the next step on the left subtree.
                          * Note that lnode has already been advanced here */
                         if (lnode >= 0) {
-                            /*printf("      Right subtree ended, continuing right subtree's left and right contour on left subtree (node %ld)\n", lnode);*/
-                            vdata[rnode].left_contour = lnode;
-                            vdata[rnode].right_contour = lnode;
-                            vdata[rnode].offset_follow_lc = vdata[rnode].offset_follow_rc =
-                                                                (loffset - roffset); /* loffset has also been increased earlier */
-                            /*printf("      vdata[rnode].offset_follow_* = %.4f\n", vdata[rnode].offset_follow_lc);*/
+                            auxnode = vdata[i].right_extreme;
+
+                            /* this is the "threading" step that the original
+                             * paper is talking about */
+                            newoffset = loffset - rootsep - vdata[i].offset_to_right_extreme;
+                            vdata[auxnode].left_contour = lnode;
+                            vdata[auxnode].right_contour = lnode;
+                            vdata[auxnode].offset_to_left_contour = vdata[auxnode].offset_to_right_contour = newoffset;
+
+                            /* no need to update the extrema of the subtree
+                             * rooted at 'node' because the right subtree was
+                             * smaller */
+#ifdef LAYOUT_RT_DEBUG
+                            printf("      Right subtree ended earlier, continuing right subtree's left and right contour on left subtree (node %ld gets connected to node %ld)\n", auxnode, lnode);
+                            printf("      New contour following offset for node %ld is %lf\n", auxnode, vdata[auxnode].offset_to_left_contour);
+#endif
                         }
                         rnode = -1;
                     }
-                    /*printf("    Contour: [%d, %d], offsets: [%lf, %lf], rootsep: %lf\n",
-                           lnode, rnode, loffset, roffset, rootsep);*/
+#ifdef LAYOUT_RT_DEBUG
+                    printf("    Contour: [%ld, %ld], offsets: [%lf, %lf], rootsep: %lf\n", 
+                           lnode, rnode, loffset, roffset, rootsep);
+#endif
 
                     /* Push subtrees away if necessary */
                     if ((lnode >= 0) && (rnode >= 0) && (roffset - loffset < minsep)) {
-                        /*printf("    Pushing right subtree away by %lf\n", minsep-roffset+loffset);*/
+#ifdef LAYOUT_RT_DEBUG
+                        printf("    Pushing right subtree away by %lf\n", minsep-roffset+loffset);
+#endif
                         rootsep += minsep - roffset + loffset;
                         roffset = loffset + minsep;
+                        vdata[node].offset_to_right_contour = rootsep;
                     }
                 }
 
-                /*printf("  Offset of subtree with root node %d will be %lf\n", i, rootsep);*/
+#ifdef LAYOUT_RT_DEBUG
+                printf("  Offset of subtree with root node %ld will be %lf\n", i, rootsep);
+#endif
                 vdata[i].offset = rootsep;
-                vdata[node].right_contour = i;
-                vdata[node].offset_follow_rc = rootsep;
+                vdata[node].offset_to_right_contour = rootsep;
                 avg = (avg * j) / (j + 1) + rootsep / (j + 1);
                 leftrootidx = j;
                 leftroot = i;
             } else {
+                /* This is the first child of the node being considered so we
+                 * can simply place the subtree on our virtual canvas */
+#ifdef LAYOUT_RT_DEBUG
+                printf("  Placing child %ld on level %ld as first child\n", i, vdata[i].level);
+#endif
                 leftrootidx = j;
                 leftroot = i;
                 vdata[node].left_contour = i;
                 vdata[node].right_contour = i;
-                vdata[node].offset_follow_lc = 0.0;
-                vdata[node].offset_follow_rc = 0.0;
+                vdata[node].offset_to_left_contour = 0.0;
+                vdata[node].offset_to_right_contour = 0.0;
+                vdata[node].left_extreme = vdata[i].left_extreme;
+                vdata[node].right_extreme = vdata[i].right_extreme;
+                vdata[node].offset_to_left_extreme = vdata[i].offset_to_left_extreme;
+                vdata[node].offset_to_right_extreme = vdata[i].offset_to_right_extreme;
                 avg = vdata[i].offset;
             }
             j++;
         }
     }
-    /*printf("Shifting node to be centered above children. Shift amount: %lf\n", avg);*/
-    vdata[node].offset_follow_lc -= avg;
-    vdata[node].offset_follow_rc -= avg;
+#ifdef LAYOUT_RT_DEBUG
+    printf("Shifting node %ld to be centered above children. Shift amount: %lf\n", node, avg);
+#endif
+    vdata[node].offset_to_left_contour -= avg;
+    vdata[node].offset_to_right_contour -= avg;
+    vdata[node].offset_to_left_extreme -= avg;
+    vdata[node].offset_to_right_extreme -= avg;
     for (i = 0, j = 0; i < vcount; i++) {
         if (i == node) {
             continue;
@@ -1419,10 +1503,12 @@
 #define COULOMBS_CONSTANT 8987500000.0
 
 
-igraph_real_t igraph_i_distance_between(const igraph_matrix_t *c, long int a,
-                                        long int b);
+static igraph_real_t igraph_i_distance_between(
+        const igraph_matrix_t *c,
+        long int a, long int b);
 
-int igraph_i_determine_electric_axal_forces(const igraph_matrix_t *pos,
+static int igraph_i_determine_electric_axal_forces(
+        const igraph_matrix_t *pos,
         igraph_real_t *x,
         igraph_real_t *y,
         igraph_real_t directed_force,
@@ -1430,14 +1516,16 @@
         long int other_node,
         long int this_node);
 
-int igraph_i_apply_electrical_force(const igraph_matrix_t *pos,
-                                    igraph_vector_t *pending_forces_x,
-                                    igraph_vector_t *pending_forces_y,
-                                    long int other_node, long int this_node,
-                                    igraph_real_t node_charge,
-                                    igraph_real_t distance);
+static int igraph_i_apply_electrical_force(
+        const igraph_matrix_t *pos,
+        igraph_vector_t *pending_forces_x,
+        igraph_vector_t *pending_forces_y,
+        long int other_node, long int this_node,
+        igraph_real_t node_charge,
+        igraph_real_t distance);
 
-int igraph_i_determine_spring_axal_forces(const igraph_matrix_t *pos,
+static int igraph_i_determine_spring_axal_forces(
+        const igraph_matrix_t *pos,
         igraph_real_t *x, igraph_real_t *y,
         igraph_real_t directed_force,
         igraph_real_t distance,
@@ -1445,27 +1533,30 @@
         long int other_node,
         long int this_node);
 
-int igraph_i_apply_spring_force(const igraph_matrix_t *pos,
-                                igraph_vector_t *pending_forces_x,
-                                igraph_vector_t *pending_forces_y,
-                                long int other_node,
-                                long int this_node, int spring_length,
-                                igraph_real_t spring_constant);
+static int igraph_i_apply_spring_force(
+        const igraph_matrix_t *pos,
+        igraph_vector_t *pending_forces_x,
+        igraph_vector_t *pending_forces_y,
+        long int other_node,
+        long int this_node, int spring_length,
+        igraph_real_t spring_constant);
 
-int igraph_i_move_nodes(igraph_matrix_t *pos,
-                        const igraph_vector_t *pending_forces_x,
-                        const igraph_vector_t *pending_forces_y,
-                        igraph_real_t node_mass,
-                        igraph_real_t max_sa_movement);
+static int igraph_i_move_nodes(
+        igraph_matrix_t *pos,
+        const igraph_vector_t *pending_forces_x,
+        const igraph_vector_t *pending_forces_y,
+        igraph_real_t node_mass,
+        igraph_real_t max_sa_movement);
 
-igraph_real_t igraph_i_distance_between(const igraph_matrix_t *c, long int a,
-                                        long int b) {
+static igraph_real_t igraph_i_distance_between(
+        const igraph_matrix_t *c,
+        long int a, long int b) {
     igraph_real_t diffx = MATRIX(*c, a, 0) - MATRIX(*c, b, 0);
     igraph_real_t diffy = MATRIX(*c, a, 1) - MATRIX(*c, b, 1);
     return sqrt( diffx * diffx + diffy * diffy );
 }
 
-int igraph_i_determine_electric_axal_forces(const igraph_matrix_t *pos,
+static int igraph_i_determine_electric_axal_forces(const igraph_matrix_t *pos,
         igraph_real_t *x,
         igraph_real_t *y,
         igraph_real_t directed_force,
@@ -1518,12 +1609,13 @@
     return 0;
 }
 
-int igraph_i_apply_electrical_force(const igraph_matrix_t *pos,
-                                    igraph_vector_t *pending_forces_x,
-                                    igraph_vector_t *pending_forces_y,
-                                    long int other_node, long int this_node,
-                                    igraph_real_t node_charge,
-                                    igraph_real_t distance) {
+static int igraph_i_apply_electrical_force(
+        const igraph_matrix_t *pos,
+        igraph_vector_t *pending_forces_x,
+        igraph_vector_t *pending_forces_y,
+        long int other_node, long int this_node,
+        igraph_real_t node_charge,
+        igraph_real_t distance) {
 
     igraph_real_t directed_force = COULOMBS_CONSTANT *
                                    ((node_charge * node_charge) / (distance * distance));
@@ -1541,7 +1633,8 @@
     return 0;
 }
 
-int igraph_i_determine_spring_axal_forces(const igraph_matrix_t *pos,
+static int igraph_i_determine_spring_axal_forces(
+        const igraph_matrix_t *pos,
         igraph_real_t *x, igraph_real_t *y,
         igraph_real_t directed_force,
         igraph_real_t distance,
@@ -1579,12 +1672,13 @@
     return 0;
 }
 
-int igraph_i_apply_spring_force(const igraph_matrix_t *pos,
-                                igraph_vector_t *pending_forces_x,
-                                igraph_vector_t *pending_forces_y,
-                                long int other_node,
-                                long int this_node, int spring_length,
-                                igraph_real_t spring_constant) {
+static int igraph_i_apply_spring_force(
+        const igraph_matrix_t *pos,
+        igraph_vector_t *pending_forces_x,
+        igraph_vector_t *pending_forces_y,
+        long int other_node,
+        long int this_node, int spring_length,
+        igraph_real_t spring_constant) {
 
     // determined using Hooke's Law:
     //   force = -kx
@@ -1625,11 +1719,12 @@
     return 0;
 }
 
-int igraph_i_move_nodes(igraph_matrix_t *pos,
-                        const igraph_vector_t *pending_forces_x,
-                        const igraph_vector_t *pending_forces_y,
-                        igraph_real_t node_mass,
-                        igraph_real_t max_sa_movement) {
+static int igraph_i_move_nodes(
+        igraph_matrix_t *pos,
+        const igraph_vector_t *pending_forces_x,
+        const igraph_vector_t *pending_forces_y,
+        igraph_real_t node_mass,
+        igraph_real_t max_sa_movement) {
 
     // Since each iteration is isolated, time is constant at 1.
     // Therefore:
@@ -1822,11 +1917,13 @@
     return 0;
 }
 
+/* not 'static', used in tests */
 int igraph_i_layout_merge_dla(igraph_i_layout_mergegrid_t *grid,
                               long int actg, igraph_real_t *x, igraph_real_t *y, igraph_real_t r,
                               igraph_real_t cx, igraph_real_t cy, igraph_real_t startr,
                               igraph_real_t killr);
 
+/* TODO: not 'static' because used in tests */
 int igraph_i_layout_sphere_2d(igraph_matrix_t *coords, igraph_real_t *x,
                               igraph_real_t *y, igraph_real_t *r);
 int igraph_i_layout_sphere_3d(igraph_matrix_t *coords, igraph_real_t *x,
@@ -1981,7 +2078,8 @@
     return 0;
 }
 
-int igraph_i_layout_sphere_2d(igraph_matrix_t *coords, igraph_real_t *x, igraph_real_t *y,
+int igraph_i_layout_sphere_2d(igraph_matrix_t *coords,
+                              igraph_real_t *x, igraph_real_t *y,
                               igraph_real_t *r) {
     long int nodes = igraph_matrix_nrow(coords);
     long int i;
@@ -2012,7 +2110,8 @@
     return 0;
 }
 
-int igraph_i_layout_sphere_3d(igraph_matrix_t *coords, igraph_real_t *x, igraph_real_t *y,
+int igraph_i_layout_sphere_3d(igraph_matrix_t *coords,
+                              igraph_real_t *x, igraph_real_t *y,
                               igraph_real_t *z, igraph_real_t *r) {
     long int nodes = igraph_matrix_nrow(coords);
     long int i;
@@ -2094,14 +2193,14 @@
     return 0;
 }
 
-int igraph_i_layout_mds_step(igraph_real_t *to, const igraph_real_t *from,
-                             int n, void *extra);
+static int igraph_i_layout_mds_step(igraph_real_t *to, const igraph_real_t *from,
+                                    int n, void *extra);
 
-int igraph_i_layout_mds_single(const igraph_t* graph, igraph_matrix_t *res,
-                               igraph_matrix_t *dist, long int dim);
+static int igraph_i_layout_mds_single(const igraph_t* graph, igraph_matrix_t *res,
+                                      igraph_matrix_t *dist, long int dim);
 
-int igraph_i_layout_mds_step(igraph_real_t *to, const igraph_real_t *from,
-                             int n, void *extra) {
+static int igraph_i_layout_mds_step(igraph_real_t *to, const igraph_real_t *from,
+                                    int n, void *extra) {
     igraph_matrix_t* matrix = (igraph_matrix_t*)extra;
     IGRAPH_UNUSED(n);
     igraph_blas_dgemv_array(0, 1, matrix, from, 0, to);
diff --git a/igraph/src/layout_dh.c b/igraph/src/layout_dh.c
--- a/igraph/src/layout_dh.c
+++ b/igraph/src/layout_dh.c
@@ -26,9 +26,11 @@
 #include "igraph_interface.h"
 #include "igraph_random.h"
 #include "igraph_math.h"
+#include "igraph_interrupt_internal.h"
 
 #include <math.h>
 
+/* not 'static', used in tests */
 igraph_bool_t igraph_i_segments_intersect(float p0_x, float p0_y,
         float p1_x, float p1_y,
         float p2_x, float p2_y,
@@ -52,6 +54,7 @@
     return s >= 0 && s <= 1 && t >= 0 && t <= 1 ? 1 : 0;
 }
 
+/* not 'static', used in tests */
 float igraph_i_point_segment_dist2(float v_x, float v_y,
                                    float u1_x, float u1_y,
                                    float u2_x, float u2_y) {
@@ -240,6 +243,8 @@
     for (round = 0; round < maxiter + fineiter; round++) {
         igraph_integer_t p;
         igraph_vector_int_shuffle(&perm);
+
+        IGRAPH_ALLOW_INTERRUPTION();
 
         fine_tuning = round >= maxiter;
         if (fine_tuning) {
diff --git a/igraph/src/layout_fr.c b/igraph/src/layout_fr.c
--- a/igraph/src/layout_fr.c
+++ b/igraph/src/layout_fr.c
@@ -28,16 +28,16 @@
 #include "igraph_components.h"
 #include "igraph_types_internal.h"
 
-int igraph_layout_i_fr(const igraph_t *graph,
-                       igraph_matrix_t *res,
-                       igraph_bool_t use_seed,
-                       igraph_integer_t niter,
-                       igraph_real_t start_temp,
-                       const igraph_vector_t *weight,
-                       const igraph_vector_t *minx,
-                       const igraph_vector_t *maxx,
-                       const igraph_vector_t *miny,
-                       const igraph_vector_t *maxy) {
+static int igraph_layout_i_fr(const igraph_t *graph,
+                              igraph_matrix_t *res,
+                              igraph_bool_t use_seed,
+                              igraph_integer_t niter,
+                              igraph_real_t start_temp,
+                              const igraph_vector_t *weight,
+                              const igraph_vector_t *minx,
+                              const igraph_vector_t *maxx,
+                              const igraph_vector_t *miny,
+                              const igraph_vector_t *maxy) {
 
     igraph_integer_t no_nodes = igraph_vcount(graph);
     igraph_integer_t no_edges = igraph_ecount(graph);
@@ -188,12 +188,13 @@
     return 0;
 }
 
-int igraph_layout_i_grid_fr(const igraph_t *graph,
-                            igraph_matrix_t *res, igraph_bool_t use_seed,
-                            igraph_integer_t niter, igraph_real_t start_temp,
-                            const igraph_vector_t *weight, const igraph_vector_t *minx,
-                            const igraph_vector_t *maxx, const igraph_vector_t *miny,
-                            const igraph_vector_t *maxy) {
+static int igraph_layout_i_grid_fr(
+        const igraph_t *graph,
+        igraph_matrix_t *res, igraph_bool_t use_seed,
+        igraph_integer_t niter, igraph_real_t start_temp,
+        const igraph_vector_t *weight, const igraph_vector_t *minx,
+        const igraph_vector_t *maxx, const igraph_vector_t *miny,
+        const igraph_vector_t *maxy) {
 
     igraph_integer_t no_nodes = igraph_vcount(graph);
     igraph_integer_t no_edges = igraph_ecount(graph);
diff --git a/igraph/src/layout_kk.c b/igraph/src/layout_kk.c
--- a/igraph/src/layout_kk.c
+++ b/igraph/src/layout_kk.c
@@ -41,8 +41,10 @@
  *        contain the result (x-positions in column zero and
  *        y-positions in column one) and will be resized if needed.
  * \param use_seed Boolean, whether to use the values supplied in the
- *        \p res argument as the initial configuration. If zero then a
- *        random initial configuration is used.
+ *        \p res argument as the initial configuration. If zero and there
+ *        are any limits on the X or Y coordinates, then a random initial
+ *        configuration is used. Otherwise the vertices are placed on a
+ *        circle of radius 1 as the initial configuration.
  * \param maxiter The maximum number of iterations to perform. A reasonable
  *        default value is at least ten (or more) times the number of
  *        vertices.
@@ -285,7 +287,7 @@
         /* Update delta, only with/for the affected node */
         VECTOR(D1)[m] = VECTOR(D2)[m] = 0.0;
         for (i = 0; i < no_nodes; i++) {
-            igraph_real_t old_dx, old_dy, old_mi, new_dx, new_dy, new_mi_dist, old_mi_dist;
+            igraph_real_t old_dx, old_dy, new_dx, new_dy, new_mi_dist, old_mi_dist;
             if (i == m) {
                 continue;
             }
@@ -340,8 +342,10 @@
  *        contain the result (x-positions in column zero and
  *        y-positions in column one) and will be resized if needed.
  * \param use_seed Boolean, whether to use the values supplied in the
- *        \p res argument as the initial configuration. If zero then a
- *        random initial configuration is used.
+ *        \p res argument as the initial configuration. If zero and there
+ *        are any limits on the X, Y or Z coordinates, then a random initial
+ *        configuration is used. Otherwise the vertices are placed uniformly
+ *        on a sphere of radius 1 as the initial configuration.
  * \param maxiter The maximum number of iterations to perform. A reasonable
  *        default value is at least ten (or more) times the number of
  *        vertices.
@@ -577,6 +581,7 @@
             dz = old_z - MATRIX(*res, i, 2);
             dist = sqrt(dx * dx + dy * dy + dz * dz);
             den = dist * (dx * dx + dy * dy + dz * dz);
+
             k_mi = MATRIX(kij, m, i);
             l_mi = MATRIX(lij, m, i);
             Axx += k_mi * (1 - l_mi * (dy * dy + dz * dz) / den);
@@ -594,9 +599,16 @@
 #define DET(a,b,c,d,e,f,g,h,i) ((a*e*i+b*f*g+c*d*h)-(c*e*g+b*d*i+a*f*h))
 
         detnum  = DET(Axx, Axy, Axz, Axy, Ayy, Ayz, Axz, Ayz, Azz);
-        delta_x = DET(Ax, Ay, Az, Axy, Ayy, Ayz, Axz, Ayz, Azz) / detnum;
-        delta_y = DET(Axx, Axy, Axz, Ax, Ay, Az, Axz, Ayz, Azz) / detnum;
-        delta_z = DET(Axx, Axy, Axz, Axy, Ayy, Ayz, Ax, Ay, Az ) / detnum;
+        if (detnum != 0) {
+            delta_x = DET(Ax, Ay, Az, Axy, Ayy, Ayz, Axz, Ayz, Azz) / detnum;
+            delta_y = DET(Axx, Axy, Axz, Ax, Ay, Az, Axz, Ayz, Azz) / detnum;
+            delta_z = DET(Axx, Axy, Axz, Axy, Ayy, Ayz, Ax, Ay, Az ) / detnum;
+        } else {
+            /* No new stable position for node m; this can happen in rare
+             * cases, e.g., if the graph has two nodes only. It's best to leave
+             * the node where it is. */
+            delta_x = delta_y = delta_z = 0;
+        }
 
         new_x = old_x + delta_x;
         new_y = old_y + delta_y;
diff --git a/igraph/src/lsap.c b/igraph/src/lsap.c
--- a/igraph/src/lsap.c
+++ b/igraph/src/lsap.c
@@ -2,12 +2,11 @@
 #include "igraph_lsap.h"
 #include "igraph_error.h"
 
-#include <stdio.h>
+/* #include <stdio.h> */
 #include <stdlib.h>
 #include <math.h>
 #include <limits.h>     /* INT_MAX */
 #include <float.h>      /* DBL_MAX */
-#include <assert.h>
 #include <time.h>
 
 /* constants used for improving readability of code */
@@ -40,30 +39,30 @@
 /* public interface */
 
 /* constructors and destructor */
-AP     *ap_create_problem(double *t, int n);
-AP     *ap_create_problem_from_matrix(double **t, int n);
-AP     *ap_read_problem(char *file);
-void    ap_free(AP *p);
+static AP     *ap_create_problem(double *t, int n);
+static AP     *ap_create_problem_from_matrix(double **t, int n);
+static AP     *ap_read_problem(char *file);
+static void    ap_free(AP *p);
 
-int     ap_assignment(AP *p, int *res);
-int     ap_costmatrix(AP *p, double **m);
-int     ap_datamatrix(AP *p, double **m);
-int     ap_iterations(AP *p);
-int     ap_hungarian(AP *p);
-double  ap_mincost(AP *p);
-void    ap_print_solution(AP *p);
-void    ap_show_data(AP *p);
-int     ap_size(AP *p);
-int     ap_time(AP *p);
+static int     ap_assignment(AP *p, int *res);
+static int     ap_costmatrix(AP *p, double **m);
+static int     ap_datamatrix(AP *p, double **m);
+static int     ap_iterations(AP *p);
+static int     ap_hungarian(AP *p);
+static double  ap_mincost(AP *p);
+/* static void    ap_print_solution(AP *p); */
+/* static void    ap_show_data(AP *p); */
+static int     ap_size(AP *p);
+static int     ap_time(AP *p);
 
 /* error reporting */
-void ap_error(char *message);
+/* static void ap_error(char *message); */
 
 /* private functions */
-void    preprocess(AP *p);
-void    preassign(AP *p);
-int     cover(AP *p, int *ri, int *ci);
-void    reduce(AP *p, int *ri, int *ci);
+static void    preprocess(AP *p);
+static void    preassign(AP *p);
+static int     cover(AP *p, int *ri, int *ci);
+static void    reduce(AP *p, int *ri, int *ci);
 
 int ap_hungarian(AP *p) {
     int      n;            /* size of problem */
diff --git a/igraph/src/matching.c b/igraph/src/matching.c
--- a/igraph/src/matching.c
+++ b/igraph/src/matching.c
@@ -21,17 +21,15 @@
 
 */
 
-#include <assert.h>
-#include <math.h>
-#include "config.h"
 #include "igraph_adjlist.h"
 #include "igraph_constructors.h"
 #include "igraph_conversion.h"
 #include "igraph_dqueue.h"
-#include "igraph_flow.h"
 #include "igraph_interface.h"
 #include "igraph_matching.h"
 #include "igraph_structural.h"
+#include "config.h"
+#include <math.h>
 
 /* #define MATCHING_DEBUG */
 
@@ -207,10 +205,12 @@
     return IGRAPH_SUCCESS;
 }
 
-int igraph_i_maximum_bipartite_matching_unweighted(const igraph_t* graph,
+static int igraph_i_maximum_bipartite_matching_unweighted(
+        const igraph_t* graph,
         const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
         igraph_vector_long_t* matching);
-int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
+static int igraph_i_maximum_bipartite_matching_weighted(
+        const igraph_t* graph,
         const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
         igraph_real_t* matching_weight, igraph_vector_long_t* matching,
         const igraph_vector_t* weights, igraph_real_t eps);
@@ -306,7 +306,8 @@
     }
 }
 
-int igraph_i_maximum_bipartite_matching_unweighted_relabel(const igraph_t* graph,
+static int igraph_i_maximum_bipartite_matching_unweighted_relabel(
+        const igraph_t* graph,
         const igraph_vector_bool_t* types, igraph_vector_t* labels,
         igraph_vector_long_t* matching, igraph_bool_t smaller_set);
 
@@ -323,7 +324,8 @@
  * Avancée en Calcul Scientifique).
  * http://www.cerfacs.fr/algor/reports/2011/TR_PA_11_33.pdf
  */
-int igraph_i_maximum_bipartite_matching_unweighted(const igraph_t* graph,
+static int igraph_i_maximum_bipartite_matching_unweighted(
+        const igraph_t* graph,
         const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
         igraph_vector_long_t* matching) {
     long int i, j, k, n, no_of_nodes = igraph_vcount(graph);
@@ -460,7 +462,8 @@
     return IGRAPH_SUCCESS;
 }
 
-int igraph_i_maximum_bipartite_matching_unweighted_relabel(const igraph_t* graph,
+static int igraph_i_maximum_bipartite_matching_unweighted_relabel(
+        const igraph_t* graph,
         const igraph_vector_bool_t* types, igraph_vector_t* labels,
         igraph_vector_long_t* match, igraph_bool_t smaller_set) {
     long int i, j, n, no_of_nodes = igraph_vcount(graph), matched_to;
@@ -529,7 +532,8 @@
  * an edge falls below \c eps, it will be considered tight. If all your
  * weights are integers, you can safely set \c eps to zero.
  */
-int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
+static int igraph_i_maximum_bipartite_matching_weighted(
+        const igraph_t* graph,
         const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
         igraph_real_t* matching_weight, igraph_vector_long_t* matching,
         const igraph_vector_t* weights, igraph_real_t eps) {
diff --git a/igraph/src/math.c b/igraph/src/math.c
--- a/igraph/src/math.c
+++ b/igraph/src/math.c
@@ -33,9 +33,7 @@
 #endif
 
 int igraph_finite(double x) {
-#ifdef isfinite
-    return isfinite(x);
-#elif HAVE_ISFINITE == 1
+#if HAVE_DECL_ISFINITE
     return isfinite(x);
 #elif HAVE_FINITE == 1
     return finite(x);
@@ -79,11 +77,13 @@
     int i;
 
     if (n < 1 || n > 1000) {
-        IGRAPH_NAN;
+        IGRAPH_WARNING("chebyshev_eval: argument out of domain");
+        return IGRAPH_NAN;
     }
 
     if (x < -1.1 || x > 1.1) {
-        IGRAPH_NAN;
+        IGRAPH_WARNING("chebyshev_eval: argument out of domain");
+        return IGRAPH_NAN;
     }
 
     twox = x * 2;
@@ -256,11 +256,11 @@
 }
 
 int igraph_is_posinf(double x) {
-    return isinf(x) == 1;
+    return isinf(x) && x > 0;
 }
 
 int igraph_is_neginf(double x) {
-    return isinf(x) == -1;
+    return isinf(x) && x < 0;
 }
 
 /**
diff --git a/igraph/src/maximal_cliques.c b/igraph/src/maximal_cliques.c
--- a/igraph/src/maximal_cliques.c
+++ b/igraph/src/maximal_cliques.c
@@ -35,13 +35,14 @@
 #define CONCAT2(a,b) CONCAT2x(a,b)
 #define FUNCTION(name,sfx) CONCAT2(name,sfx)
 
-int igraph_i_maximal_cliques_reorder_adjlists(
-    const igraph_vector_int_t *PX,
-    int PS, int PE, int XS, int XE,
-    const igraph_vector_int_t *pos,
-    igraph_adjlist_t *adjlist);
+static int igraph_i_maximal_cliques_reorder_adjlists(
+        const igraph_vector_int_t *PX,
+        int PS, int PE, int XS, int XE,
+        const igraph_vector_int_t *pos,
+        igraph_adjlist_t *adjlist);
 
-int igraph_i_maximal_cliques_select_pivot(const igraph_vector_int_t *PX,
+static int igraph_i_maximal_cliques_select_pivot(
+        const igraph_vector_int_t *PX,
         int PS, int PE, int XS, int XE,
         const igraph_vector_int_t *pos,
         const igraph_adjlist_t *adjlist,
@@ -49,23 +50,26 @@
         igraph_vector_int_t *nextv,
         int oldPS, int oldXE);
 
-int igraph_i_maximal_cliques_down(igraph_vector_int_t *PX,
-                                  int PS, int PE, int XS, int XE,
-                                  igraph_vector_int_t *pos,
-                                  igraph_adjlist_t *adjlist, int mynextv,
-                                  igraph_vector_int_t *R,
-                                  int *newPS, int *newXE);
+static int igraph_i_maximal_cliques_down(
+        igraph_vector_int_t *PX,
+        int PS, int PE, int XS, int XE,
+        igraph_vector_int_t *pos,
+        igraph_adjlist_t *adjlist, int mynextv,
+        igraph_vector_int_t *R,
+        int *newPS, int *newXE);
 
-int igraph_i_maximal_cliques_PX(igraph_vector_int_t *PX, int PS, int *PE,
-                                int *XS, int XE, igraph_vector_int_t *pos,
-                                igraph_adjlist_t *adjlist, int v,
-                                igraph_vector_int_t *H);
+static int igraph_i_maximal_cliques_PX(
+        igraph_vector_int_t *PX, int PS, int *PE,
+        int *XS, int XE, igraph_vector_int_t *pos,
+        igraph_adjlist_t *adjlist, int v,
+        igraph_vector_int_t *H);
 
-int igraph_i_maximal_cliques_up(igraph_vector_int_t *PX, int PS, int PE,
-                                int XS, int XE, igraph_vector_int_t *pos,
-                                igraph_adjlist_t *adjlist,
-                                igraph_vector_int_t *R,
-                                igraph_vector_int_t *H);
+static int igraph_i_maximal_cliques_up(
+        igraph_vector_int_t *PX, int PS, int PE,
+        int XS, int XE, igraph_vector_int_t *pos,
+        igraph_adjlist_t *adjlist,
+        igraph_vector_int_t *R,
+        igraph_vector_int_t *H);
 
 #define PRINT_PX do {                              \
         int j;                                 \
@@ -109,11 +113,11 @@
         printf("\n");                              \
     } while (0)
 
-int igraph_i_maximal_cliques_reorder_adjlists(
-    const igraph_vector_int_t *PX,
-    int PS, int PE, int XS, int XE,
-    const igraph_vector_int_t *pos,
-    igraph_adjlist_t *adjlist) {
+static int igraph_i_maximal_cliques_reorder_adjlists(
+        const igraph_vector_int_t *PX,
+        int PS, int PE, int XS, int XE,
+        const igraph_vector_int_t *pos,
+        igraph_adjlist_t *adjlist) {
     int j;
     int sPS = PS + 1, sPE = PE + 1;
 
@@ -140,7 +144,8 @@
     return 0;
 }
 
-int igraph_i_maximal_cliques_select_pivot(const igraph_vector_int_t *PX,
+static int igraph_i_maximal_cliques_select_pivot(
+        const igraph_vector_int_t *PX,
         int PS, int PE, int XS, int XE,
         const igraph_vector_int_t *pos,
         const igraph_adjlist_t *adjlist,
@@ -216,12 +221,12 @@
         VECTOR(*pos)[v2] = (p1)+1;          \
     } while (0)
 
-int igraph_i_maximal_cliques_down(igraph_vector_int_t *PX,
-                                  int PS, int PE, int XS, int XE,
-                                  igraph_vector_int_t *pos,
-                                  igraph_adjlist_t *adjlist, int mynextv,
-                                  igraph_vector_int_t *R,
-                                  int *newPS, int *newXE) {
+static int igraph_i_maximal_cliques_down(igraph_vector_int_t *PX,
+                                         int PS, int PE, int XS, int XE,
+                                         igraph_vector_int_t *pos,
+                                         igraph_adjlist_t *adjlist, int mynextv,
+                                         igraph_vector_int_t *R,
+                                         int *newPS, int *newXE) {
 
     igraph_vector_int_t *vneis = igraph_adjlist_get(adjlist, mynextv);
     int j, vneislen = igraph_vector_int_size(vneis);
@@ -247,10 +252,10 @@
 
 #undef SWAP
 
-int igraph_i_maximal_cliques_PX(igraph_vector_int_t *PX, int PS, int *PE,
-                                int *XS, int XE, igraph_vector_int_t *pos,
-                                igraph_adjlist_t *adjlist, int v,
-                                igraph_vector_int_t *H) {
+static int igraph_i_maximal_cliques_PX(igraph_vector_int_t *PX, int PS, int *PE,
+                                       int *XS, int XE, igraph_vector_int_t *pos,
+                                       igraph_adjlist_t *adjlist, int v,
+                                       igraph_vector_int_t *H) {
 
     int vpos = VECTOR(*pos)[v] - 1;
     int tmp = VECTOR(*PX)[*PE];
@@ -264,11 +269,11 @@
     return 0;
 }
 
-int igraph_i_maximal_cliques_up(igraph_vector_int_t *PX, int PS, int PE,
-                                int XS, int XE, igraph_vector_int_t *pos,
-                                igraph_adjlist_t *adjlist,
-                                igraph_vector_int_t *R,
-                                igraph_vector_int_t *H) {
+static int igraph_i_maximal_cliques_up(igraph_vector_int_t *PX, int PS, int PE,
+                                       int XS, int XE, igraph_vector_int_t *pos,
+                                       igraph_adjlist_t *adjlist,
+                                       igraph_vector_int_t *R,
+                                       igraph_vector_int_t *H) {
     int vv;
     igraph_vector_int_pop_back(R);
 
@@ -287,7 +292,7 @@
 
 /**
  * \function igraph_maximal_cliques
- * \brief Find all maximal cliques of a graph
+ * \brief Finds all maximal cliques in a graph.
  *
  * </para><para>
  * A maximal clique is a clique which can't be extended any more by
@@ -311,7 +316,7 @@
  *
  * \param graph The input graph.
  * \param res Pointer to a pointer vector, the result will be stored
- *   here, ie. \c res will contain pointers to \c igraph_vector_t
+ *   here, i.e. \p res will contain pointers to \ref igraph_vector_t
  *   objects which contain the indices of vertices involved in a clique.
  *   The pointer vector will be resized if needed but note that the
  *   objects in the pointer vector will not be freed. Note that vertices
@@ -415,11 +420,11 @@
 
 /**
  * \function igraph_maximal_cliques_callback
- * \brief Finds maximal cliques in a graph and calls a function for each one
+ * \brief Finds maximal cliques in a graph and calls a function for each one.
  *
  * This function enumerates all maximal cliques within the given size range
  * and calls \p cliquehandler_fn for each of them. The cliques are passed to the
- * callback function as an <type>igraph_vector_t *</type>.  Destroying and
+ * callback function as a pointer to an \ref igraph_vector_t.  Destroying and
  * freeing this vector is left up to the user.  Use \ref igraph_vector_destroy()
  * to destroy it first, then free it using \ref igraph_free().
  *
@@ -457,7 +462,7 @@
 
 /**
  * \function igraph_maximal_cliques_hist
- * \brief Count the number of maximal cliques of each size in a graph.
+ * \brief Counts the number of maximal cliques of each size in a graph.
  *
  * This function counts how many maximal cliques of each size are present in
  * the graph. Size-1 maximal cliques are simply isolated vertices.
@@ -472,7 +477,7 @@
  * \param hist Pointer to an initialized vector. The result will be stored
  * here. The first element will store the number of size-1 maximal cliques,
  * the second element the number of size-2 maximal cliques, etc.
- * For cliques smaller than \c min_size, zero counts will be returned.
+ * For cliques smaller than \p min_size, zero counts will be returned.
  * \param min_size Integer giving the minimum size of the cliques to be
  *   returned. If negative or zero, no lower bound will be used.
  * \param max_size Integer giving the maximum size of the cliques to be
diff --git a/igraph/src/motifs.c b/igraph/src/motifs.c
--- a/igraph/src/motifs.c
+++ b/igraph/src/motifs.c
@@ -27,31 +27,17 @@
 #include "igraph_adjlist.h"
 #include "igraph_interrupt_internal.h"
 #include "igraph_interface.h"
+#include "igraph_isoclasses.h"
 #include "igraph_nongraph.h"
-#include "igraph_structural.h"
 #include "igraph_stack.h"
 #include "config.h"
 
-#include <string.h>
-
-extern unsigned int igraph_i_isoclass_3[];
-extern unsigned int igraph_i_isoclass_4[];
-extern unsigned int igraph_i_isoclass_3u[];
-extern unsigned int igraph_i_isoclass_4u[];
-extern unsigned int igraph_i_isoclass2_3[];
-extern unsigned int igraph_i_isoclass2_4[];
-extern unsigned int igraph_i_isoclass2_3u[];
-extern unsigned int igraph_i_isoclass2_4u[];
-extern unsigned int igraph_i_isoclass_3_idx[];
-extern unsigned int igraph_i_isoclass_4_idx[];
-extern unsigned int igraph_i_isoclass_3u_idx[];
-extern unsigned int igraph_i_isoclass_4u_idx[];
-
 /**
  * Callback function for igraph_motifs_randesu that counts the motifs by
  * isomorphism class in a histogram.
  */
-igraph_bool_t igraph_i_motifs_randesu_update_hist(const igraph_t *graph,
+static igraph_bool_t igraph_i_motifs_randesu_update_hist(
+        const igraph_t *graph,
         igraph_vector_t *vids, int isoclass, void* extra) {
     igraph_vector_t *hist = (igraph_vector_t*)extra;
     IGRAPH_UNUSED(graph); IGRAPH_UNUSED(vids);
@@ -65,14 +51,14 @@
  *
  * </para><para>
  * Motifs are small connected subgraphs of a given structure in a
- * graph. It is argued that the motif profile (ie. the number of
+ * graph. It is argued that the motif profile (i.e. the number of
  * different motifs in the graph) is characteristic for different
  * types of networks and network function is related to the motifs in
  * the graph.
  *
  * </para><para>
  * This function is able to find the different motifs of size three
- * and four (ie. the number of different subgraphs with three and four
+ * and four (i.e. the number of different subgraphs with three and four
  * vertices) in the network.
  *
  * </para><para>
@@ -108,7 +94,7 @@
  *        in a graph.
  * \return Error code.
  * \sa \ref igraph_motifs_randesu_estimate() for estimating the number
- * of motifs in a graph, this can help to set the \c cut_prob
+ * of motifs in a graph, this can help to set the \p cut_prob
  * parameter; \ref igraph_motifs_randesu_no() to calculate the total
  * number of motifs of a given size in a graph;
  * \ref igraph_motifs_randesu_callback() for calling a callback function
@@ -169,14 +155,14 @@
  *
  * </para><para>
  * Similarly to \ref igraph_motifs_randesu(), this function is able to find the
- * different motifs of size three and four (ie. the number of different
+ * different motifs of size three and four (i.e. the number of different
  * subgraphs with three and four vertices) in the network. However, instead of
  * counting them, the function will call a callback function for each motif
  * found to allow further tests or post-processing.
  *
  * </para><para>
- * The \c cut_prob argument also allows sampling the motifs, just like for
- * \ref igraph_motifs_randesu(). Set the \c cut_prob argument to a zero vector
+ * The \p cut_prob argument also allows sampling the motifs, just like for
+ * \ref igraph_motifs_randesu(). Set the \p cut_prob argument to a zero vector
  * for finding all motifs.
  *
  * \param graph The graph to find the motifs in.
@@ -214,7 +200,7 @@
     long int *added;
     char *subg;
 
-    unsigned int *arr_idx, *arr_code;
+    const unsigned int *arr_idx, *arr_code;
     int code = 0;
     unsigned char mul, idx;
 
@@ -447,7 +433,7 @@
  * </para><para>
  * The total number of motifs is estimated by taking a sample of
  * vertices and counts all motifs in which these vertices are
- * included. (There is also a \c cut_prob parameter which gives the
+ * included. (There is also a \p cut_prob parameter which gives the
  * probabilities to cut a branch of the search tree.)
  *
  * </para><para>
@@ -658,12 +644,9 @@
  * \brief Count the total number of motifs in a graph
  *
  * </para><para>
- * This function counts the total number of motifs in a graph without
- * assigning isomorphism classes to them.
- *
- * </para><para>
- * Directed motifs will be counted in directed graphs and undirected
- * motifs in undirected graphs.
+ * This function counts the total number of motifs in a graph,
+ * i.e. the number of of (weakly) connected triplets or quadruplets,
+ * without assigning isomorphism classes to them.
  *
  * \param graph The graph object to study.
  * \param no Pointer to an integer type, the result will be stored
diff --git a/igraph/src/mt.c b/igraph/src/mt.c
new file mode 100644
--- /dev/null
+++ b/igraph/src/mt.c
@@ -0,0 +1,95 @@
+/* mt.c
+ *
+ * Mersenne Twister random number generator, based on the implementation of
+ * Michael Brundage (which has been placed in the public domain).
+ *
+ * Author: Tamas Nepusz (original by Michael Brundage)
+ *
+ * See the following URL for the original implementation:
+ * http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation.html
+ *
+ * This file has been placed in the public domain.
+ */
+
+#include <stdlib.h>
+
+#include "igraph_random.h"
+
+#include "mt.h"
+
+static uint16_t get_random_uint16() {
+    return RNG_INT31() & 0xFFFF;
+}
+
+void mt_init(mt_rng_t* rng) {
+    mt_init_from_rng(rng, 0);
+}
+
+void mt_init_from_rng(mt_rng_t* rng, mt_rng_t* seeder) {
+    int i;
+
+    if (seeder == 0) {
+        for (i = 0; i < MT_LEN; i++) {
+            /* RAND_MAX is guaranteed to be at least 32767, so we can use two
+             * calls to rand() to produce a random 32-bit number */
+            rng->mt_buffer[i] = (get_random_uint16() << 16) + get_random_uint16();
+        }
+    } else {
+        for (i = 0; i < MT_LEN; i++) {
+            rng->mt_buffer[i] = mt_random(seeder);
+        }
+    }
+
+    rng->mt_index = 0;
+}
+
+#define MT_IA           397
+#define MT_IB           (MT_LEN - MT_IA)
+#define UPPER_MASK      0x80000000
+#define LOWER_MASK      0x7FFFFFFF
+#define MATRIX_A        0x9908B0DF
+#define TWIST(b,i,j)    ((b)[i] & UPPER_MASK) | ((b)[j] & LOWER_MASK)
+#define MAGIC(s)        (((s)&1)*MATRIX_A)
+
+uint32_t mt_random(mt_rng_t* rng) {
+    uint32_t * b = rng->mt_buffer;
+    int idx = rng->mt_index;
+    uint32_t s;
+    int i;
+	
+    if (idx == MT_LEN * sizeof(uint32_t)) {
+        idx = 0;
+        i = 0;
+        for (; i < MT_IB; i++) {
+            s = TWIST(b, i, i+1);
+            b[i] = b[i + MT_IA] ^ (s >> 1) ^ MAGIC(s);
+        }
+        for (; i < MT_LEN-1; i++) {
+            s = TWIST(b, i, i+1);
+            b[i] = b[i - MT_IB] ^ (s >> 1) ^ MAGIC(s);
+        }
+        
+        s = TWIST(b, MT_LEN-1, 0);
+        b[MT_LEN-1] = b[MT_IA-1] ^ (s >> 1) ^ MAGIC(s);
+    }
+
+    rng->mt_index = idx + sizeof(uint32_t);
+    return *(uint32_t *)((unsigned char *)b + idx);
+    /*
+    Matsumoto and Nishimura additionally confound the bits returned to the caller
+    but this doesn't increase the randomness, and slows down the generator by
+    as much as 25%.  So I omit these operations here.
+    
+    r ^= (r >> 11);
+    r ^= (r << 7) & 0x9D2C5680;
+    r ^= (r << 15) & 0xEFC60000;
+    r ^= (r >> 18);
+    */
+}
+
+
+double mt_uniform_01(mt_rng_t* rng) {
+    return ((double)mt_random(rng)) / MT_RAND_MAX;
+}
+
+
diff --git a/igraph/src/operators.c b/igraph/src/operators.c
--- a/igraph/src/operators.c
+++ b/igraph/src/operators.c
@@ -31,8 +31,8 @@
 #include "igraph_attributes.h"
 #include "igraph_conversion.h"
 #include "igraph_qsort.h"
-#include <limits.h>
 #include "config.h"
+#include <limits.h>
 
 /**
  * \function igraph_disjoint_union
@@ -47,7 +47,7 @@
  * and |E1|+|E2| edges.
  *
  * </para><para>
- * Both graphs need to have the same directedness, ie. either both
+ * Both graphs need to have the same directedness, i.e. either both
  * directed or both undirected.
  *
  * </para><para>
@@ -119,7 +119,7 @@
  * of vertices and edges in the graphs.
  *
  * </para><para>
- * Both graphs need to have the same directedness, ie. either both
+ * Both graphs need to have the same directedness, i.e. either both
  * directed or both undirected.
  *
  * </para><para>
@@ -183,8 +183,7 @@
     return 0;
 }
 
-int igraph_i_order_edgelist_cmp(void *edges, const void *e1,
-                                const void *e2) {
+static int igraph_i_order_edgelist_cmp(void *edges, const void *e1, const void *e2) {
     igraph_vector_t *edgelist = edges;
     long int edge1 = (*(const long int*) e1) * 2;
     long int edge2 = (*(const long int*) e2) * 2;
@@ -210,9 +209,9 @@
 #define IGRAPH_MODE_UNION        1
 #define IGRAPH_MODE_INTERSECTION 2
 
-int igraph_i_merge(igraph_t *res, int mode,
-                   const igraph_t *left, const igraph_t *right,
-                   igraph_vector_t *edge_map1, igraph_vector_t *edge_map2) {
+static int igraph_i_merge(igraph_t *res, int mode,
+                          const igraph_t *left, const igraph_t *right,
+                          igraph_vector_t *edge_map1, igraph_vector_t *edge_map2) {
 
     long int no_of_nodes_left = igraph_vcount(left);
     long int no_of_nodes_right = igraph_vcount(right);
@@ -431,7 +430,7 @@
                           edge_map1, edge_map2);
 }
 
-void igraph_i_union_many_free(igraph_vector_ptr_t *v) {
+static void igraph_i_union_many_free(igraph_vector_ptr_t *v) {
     long int i, n = igraph_vector_ptr_size(v);
     for (i = 0; i < n; i++) {
         if (VECTOR(*v)[i] != 0) {
@@ -442,7 +441,7 @@
     igraph_vector_ptr_destroy(v);
 }
 
-void igraph_i_union_many_free2(igraph_vector_ptr_t *v) {
+static void igraph_i_union_many_free2(igraph_vector_ptr_t *v) {
     long int i, n = igraph_vector_ptr_size(v);
     for (i = 0; i < n; i++) {
         if (VECTOR(*v)[i] != 0) {
@@ -453,7 +452,7 @@
     igraph_vector_ptr_destroy(v);
 }
 
-void igraph_i_union_many_free3(igraph_vector_ptr_t *v) {
+static void igraph_i_union_many_free3(igraph_vector_ptr_t *v) {
     long int i, n = igraph_vector_ptr_size(v);
     for (i = 0; i < n; i++) {
         if (VECTOR(*v)[i] != 0) {
@@ -469,8 +468,8 @@
  *
  * </para><para>
  * This function calculates the intersection of the graphs stored in
- * the \c graphs argument. Only those edges will be included in the
- * result graph which are part of every graph in \c graphs.
+ * the \p graphs argument. Only those edges will be included in the
+ * result graph which are part of every graph in \p graphs.
  *
  * </para><para>
  * The number of vertices in the result graph will be the maximum
@@ -492,7 +491,7 @@
  * igraph_difference() for other operators.
  *
  * Time complexity: O(|V|+|E|), |V| is the number of vertices,
- * |E| is the number of edges in the smallest graph (ie. the graph having
+ * |E| is the number of edges in the smallest graph (i.e. the graph having
  * the less vertices).
  */
 
@@ -924,9 +923,9 @@
  *
  * </para><para>
  * The number of vertices in the result is the number of vertices in
- * the original graph, ie. the left, first operand. In the results
- * graph only edges will be included from \c orig which are not
- * present in \c sub.
+ * the original graph, i.e. the left, first operand. In the results
+ * graph only edges will be included from \p orig which are not
+ * present in \p sub.
  *
  * \param res Pointer to an uninitialized graph object, the result
  * will be stored here.
@@ -999,6 +998,10 @@
                 IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
                 IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
                 n1--;
+                /* handle loop edges properly in undirected graphs */
+                if (!directed && i == v1) {
+                    n1--;
+                }
             } else if (v2 > v1) {
                 n2--;
             } else {
@@ -1015,6 +1018,11 @@
                 IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1));
                 IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
                 IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
+
+                /* handle loop edges properly in undirected graphs */
+                if (!directed && v1 == i) {
+                    n1--;
+                }
             }
             n1--;
         }
@@ -1032,6 +1040,11 @@
                 IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1));
                 IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
                 IGRAPH_CHECK(igraph_vector_push_back(&edges, v1));
+
+                /* handle loop edges properly in undirected graphs */
+                if (!directed && v1 == i) {
+                    n1--;
+                }
             }
             n1--;
         }
diff --git a/igraph/src/optimal_modularity.c b/igraph/src/optimal_modularity.c
--- a/igraph/src/optimal_modularity.c
+++ b/igraph/src/optimal_modularity.c
@@ -23,7 +23,6 @@
 */
 
 #include "igraph_interface.h"
-#include "igraph_structural.h"
 #include "igraph_community.h"
 #include "igraph_error.h"
 #include "igraph_glpk_support.h"
diff --git a/igraph/src/options.c b/igraph/src/options.c
--- a/igraph/src/options.c
+++ b/igraph/src/options.c
@@ -4,14 +4,14 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
+ * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -21,18 +21,24 @@
 #include "plfit.h"
 
 const plfit_continuous_options_t plfit_continuous_default_options = {
-  /* .finite_size_correction = */ 0,
-  /* .xmin_method = */ PLFIT_GSS_OR_LINEAR
+    /* .finite_size_correction = */ 0,
+    /* .xmin_method = */ PLFIT_DEFAULT_CONTINUOUS_METHOD,
+    /* .p_value_method = */ PLFIT_DEFAULT_P_VALUE_METHOD,
+    /* .p_value_precision = */ 0.01,
+    /* .rng = */ 0
 };
 
 const plfit_discrete_options_t plfit_discrete_default_options = {
-  /* .finite_size_correction = */ 0,
-  /* .alpha_method = */ PLFIT_LBFGS,
-  /* .alpha = */ {
-    /* .min = */ 1.01,
-    /* .max = */ 5,
-    /* .step = */ 0.01
-  }
+    /* .finite_size_correction = */ 0,
+    /* .alpha_method = */ PLFIT_DEFAULT_DISCRETE_METHOD,
+    /* .alpha = */ {
+        /* .min = */ 1.01,
+        /* .max = */ 5,
+        /* .step = */ 0.01
+    },
+    /* .p_value_method = */ PLFIT_DEFAULT_P_VALUE_METHOD,
+    /* .p_value_precision = */ 0.01,
+    /* .rng = */ 0
 };
 
 int plfit_continuous_options_init(plfit_continuous_options_t* options) {
@@ -44,4 +50,3 @@
 	*options = plfit_discrete_default_options;
 	return PLFIT_SUCCESS;
 }
-
diff --git a/igraph/src/orbit.cc b/igraph/src/orbit.cc
--- a/igraph/src/orbit.cc
+++ b/igraph/src/orbit.cc
@@ -1,5 +1,5 @@
-#include <stdlib.h>
-#include <assert.h>
+#include <cstdlib>
+#include <cassert>
 #include "defs.hh"
 #include "orbit.hh"
 
diff --git a/igraph/src/other.c b/igraph/src/other.c
--- a/igraph/src/other.c
+++ b/igraph/src/other.c
@@ -22,16 +22,13 @@
 */
 
 #include "igraph_nongraph.h"
+#include "igraph_random.h"
 #include "igraph_types.h"
-#include "igraph_memory.h"
 #include "igraph_interrupt_internal.h"
-#include "igraph_types_internal.h"
 #include "config.h"
 #include "plfit/error.h"
 #include "plfit/plfit.h"
 #include <math.h>
-#include <stdarg.h>
-#include <string.h>
 
 /**
  * \ingroup nongraph
@@ -356,9 +353,13 @@
         }
     }
 
+    RNG_BEGIN();
+
     plfit_stored_error_handler = plfit_set_error_handler(igraph_i_plfit_error_handler_store);
     if (discrete) {
         plfit_discrete_options_init(&disc_options);
+        /* approximation method should be switched to PLFIT_P_VALUE_EXACT in igraph 0.9 */
+        disc_options.p_value_method = PLFIT_P_VALUE_APPROXIMATE;
         disc_options.finite_size_correction = (plfit_bool_t) finite_size_correction;
 
         if (xmin >= 0) {
@@ -369,6 +370,10 @@
         }
     } else {
         plfit_continuous_options_init(&cont_options);
+        /* approximation method should be switched to PLFIT_P_VALUE_EXACT in igraph 0.9 */
+        cont_options.p_value_method = PLFIT_P_VALUE_APPROXIMATE;
+        /* xmin method should be switched to PLFIT_STRATIFIED_SAMPLING in igraph 0.9 */
+        cont_options.xmin_method = PLFIT_GSS_OR_LINEAR;
         cont_options.finite_size_correction = (plfit_bool_t) finite_size_correction;
 
         if (xmin >= 0) {
@@ -379,6 +384,8 @@
         }
     }
     plfit_set_error_handler(plfit_stored_error_handler);
+
+    RNG_END();
 
     switch (retval) {
     case PLFIT_FAILURE:
diff --git a/igraph/src/partition.cc b/igraph/src/partition.cc
--- a/igraph/src/partition.cc
+++ b/igraph/src/partition.cc
@@ -1,4 +1,4 @@
-#include <assert.h>
+#include <cassert>
 #include <vector>
 #include <list>
 #include "graph.hh"
@@ -344,7 +344,7 @@
 } 
 
 
-
+#if 0
 size_t
 Partition::print(FILE* const fp, const bool add_newline) const
 {
@@ -388,7 +388,7 @@
   if(add_newline) r += fprintf(fp, "\n");
   return r;
 }
-
+#endif
 
 
 void
diff --git a/igraph/src/paths.c b/igraph/src/paths.c
--- a/igraph/src/paths.c
+++ b/igraph/src/paths.c
@@ -21,6 +21,7 @@
 
 */
 
+#include "igraph_paths.h"
 #include "igraph_interface.h"
 #include "igraph_interrupt_internal.h"
 #include "igraph_vector_ptr.h"
diff --git a/igraph/src/platform.c b/igraph/src/platform.c
new file mode 100644
--- /dev/null
+++ b/igraph/src/platform.c
@@ -0,0 +1,36 @@
+/* platform.c
+ *
+ * Copyright (C) 2014 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "platform.h"
+
+#ifdef _MSC_VER
+
+inline double _plfit_fmin(double a, double b) {
+	return (a < b) ? a : b;
+}
+
+inline double _plfit_round(double x) {
+	return floor(x+0.5);
+}
+
+#endif
+
+/* Dummy function to prevent a warning when compiling with Clang - the file
+ * would contain no symbols */
+void _plfit_i_unused() {}
diff --git a/igraph/src/plfit.c b/igraph/src/plfit.c
--- a/igraph/src/plfit.c
+++ b/igraph/src/plfit.c
@@ -1,778 +1,1309 @@
-/* plfit.c
- *
- * Copyright (C) 2010-2011 Tamas Nepusz
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
- * your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <stdio.h>
-#include <float.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include "error.h"
-#include "gss.h"
-#include "lbfgs.h"
-#include "platform.h"
-#include "plfit.h"
-#include "kolmogorov.h"
-#include "zeta.h"
-
-/* #define PLFIT_DEBUG */
-
-#define DATA_POINTS_CHECK \
-    if (n <= 0) { \
-        PLFIT_ERROR("no data points", PLFIT_EINVAL); \
-    }
-
-#define XMIN_CHECK_ZERO \
-    if (xmin <= 0) { \
-        PLFIT_ERROR("xmin must be greater than zero", PLFIT_EINVAL); \
-    }
-#define XMIN_CHECK_ONE \
-    if (xmin < 1) { \
-        PLFIT_ERROR("xmin must be at least 1", PLFIT_EINVAL); \
-    }
-
-static int double_comparator(const void *a, const void *b) {
-    const double *da = (const double*)a;
-    const double *db = (const double*)b;
-    return (*da > *db) - (*da < *db);
-}
-
-/**
- * Given a sorted array of doubles, return another array that contains pointers
- * into the array for the start of each block of identical elements.
- *
- * \param  begin          pointer to the beginning of the array
- * \param  end            pointer to the first element after the end of the array
- * \param  result_length  if not \c NULL, the number of unique elements in the
- *                        given array is returned here
- */
-static double** unique_element_pointers(double* begin, double* end, size_t* result_length) {
-    double* ptr = begin;
-    double** result;
-    double prev_x;
-    size_t num_elts = 15;
-    size_t used_elts = 0;
-
-    /* Special case: empty array */
-    if (begin == end) {
-        result = calloc(1, sizeof(double*));
-        if (result != 0) {
-            result[0] = 0;
-        }
-        return result;
-    }
-
-    /* Allocate initial result array, including the guard element */
-    result = calloc(num_elts+1, sizeof(double*));
-    if (result == 0)
-        return 0;
-
-    prev_x = *begin;
-    result[used_elts++] = begin;
-
-    /* Process the input array */
-    for (ptr = begin+1; ptr < end; ptr++) {
-        if (*ptr == prev_x)
-            continue;
-
-        /* New block found */
-        if (used_elts >= num_elts) {
-            /* Array full; allocate a new chunk */
-            num_elts = num_elts*2 + 1;
-            result = realloc(result, sizeof(double*) * (num_elts+1));
-            if (result == 0)
-                return 0;
-        }
-
-        /* Store the new element */
-        result[used_elts++] = ptr;
-        prev_x = *ptr;
-    }
-
-    /* Calculate the result length */
-    if (result_length != 0) {
-        *result_length = used_elts;
-    }
-
-    /* Add the guard entry to the end of the result */
-    result[used_elts++] = 0;
-
-    return result;
-}
-
-static void plfit_i_perform_finite_size_correction(plfit_result_t* result, size_t n) {
-    result->alpha = result->alpha * (n-1) / n + 1.0 / n;
-}
-
-/********** Continuous power law distribution fitting **********/
-
-void plfit_i_logsum_less_than_continuous(double* begin, double* end,
-        double xmin, double* result, size_t* m) {
-    double logsum = 0.0;
-    size_t count = 0;
-
-    for (; begin != end; begin++) {
-        if (*begin >= xmin) {
-            count++;
-            logsum += log(*begin / xmin);
-        }
-    }
-
-    *m = count;
-    *result = logsum;
-}
-
-double plfit_i_logsum_continuous(double* begin, double* end, double xmin) {
-    double logsum = 0.0;
-    for (; begin != end; begin++)
-        logsum += log(*begin / xmin);
-    return logsum;
-}
-
-int plfit_i_estimate_alpha_continuous(double* xs, size_t n,
-        double xmin, double* alpha) {
-    double result;
-    size_t m;
-
-    XMIN_CHECK_ZERO;
-
-    plfit_i_logsum_less_than_continuous(xs, xs+n, xmin, &result, &m);
-
-    if (m == 0) {
-        PLFIT_ERROR("no data point was larger than xmin", PLFIT_EINVAL);
-    }
-
-    *alpha = 1 + m / result;
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_i_estimate_alpha_continuous_sorted(double* xs, size_t n,
-        double xmin, double* alpha) {
-	double* end = xs+n;
-
-    XMIN_CHECK_ZERO;
-
-    for (; xs != end && *xs < xmin; xs++);
-    if (xs == end) {
-        PLFIT_ERROR("no data point was larger than xmin", PLFIT_EINVAL);
-    }
-
-    *alpha = 1 + (end-xs) / plfit_i_logsum_continuous(xs, end, xmin);
-
-    return PLFIT_SUCCESS;
-}
-
-static int plfit_i_ks_test_continuous(double* xs, double* xs_end,
-        const double alpha, const double xmin, double* D) {
-    /* Assumption: xs is sorted and cut off at xmin so the first element is
-     * always larger than or equal to xmin. */
-    double result = 0, n;
-    int m = 0;
-
-    n = xs_end - xs;
-
-    while (xs < xs_end) {
-        double d = fabs(1-pow(xmin / *xs, alpha-1) - m / n);
-
-        if (d > result)
-            result = d;
-
-        xs++; m++;
-    }
-
-    *D = result;
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_log_likelihood_continuous(double* xs, size_t n, double alpha,
-        double xmin, double* L) {
-    double logsum, c;
-    size_t m;
-
-    if (alpha <= 1) {
-        PLFIT_ERROR("alpha must be greater than one", PLFIT_EINVAL);
-    }
-    XMIN_CHECK_ZERO;
-
-    c = (alpha - 1) / xmin;
-    plfit_i_logsum_less_than_continuous(xs, xs+n, xmin, &logsum, &m);
-    *L = -alpha * logsum + log(c) * m;
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_estimate_alpha_continuous(double* xs, size_t n, double xmin,
-        const plfit_continuous_options_t* options, plfit_result_t *result) {
-    double *xs_copy;
-
-	if (!options)
-		options = &plfit_continuous_default_options;
-
-    /* Make a copy of xs and sort it */
-    xs_copy = (double*)malloc(sizeof(double) * n);
-    memcpy(xs_copy, xs, sizeof(double) * n);
-    qsort(xs_copy, n, sizeof(double), double_comparator);
-
-    PLFIT_CHECK(plfit_estimate_alpha_continuous_sorted(xs_copy, n, xmin,
-				options, result));
-
-    free(xs_copy);
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_estimate_alpha_continuous_sorted(double* xs, size_t n, double xmin,
-        const plfit_continuous_options_t* options, plfit_result_t *result) {
-    double* end;
-
-	if (!options)
-		options = &plfit_continuous_default_options;
-
-	end = xs + n;
-    while (xs < end && *xs < xmin)
-        xs++;
-    n = (size_t) (end - xs);
-
-    PLFIT_CHECK(plfit_i_estimate_alpha_continuous_sorted(xs, n,
-				xmin, &result->alpha));
-    PLFIT_CHECK(plfit_i_ks_test_continuous(xs, end, result->alpha,
-				xmin, &result->D));
-
-    if (options->finite_size_correction)
-        plfit_i_perform_finite_size_correction(result, n);
-    result->xmin = xmin;
-    result->p = plfit_ks_test_one_sample_p(result->D, n);
-    plfit_log_likelihood_continuous(xs, n, result->alpha, result->xmin, &result->L);
-
-    return PLFIT_SUCCESS;
-}
-
-typedef struct {
-	double *begin;        /**< Pointer to the beginning of the array holding the data */
-	double *end;          /**< Pointer to after the end of the array holding the data */
-	double **uniques;     /**< Pointers to unique elements of the input array */
-	plfit_result_t last;  /**< Result of the last evaluation */
-} plfit_continuous_xmin_opt_data_t;
-
-double plfit_i_continuous_xmin_opt_evaluate(void* instance, double x) {
-	plfit_continuous_xmin_opt_data_t* data = (plfit_continuous_xmin_opt_data_t*)instance;
-	double* begin = data->uniques[(int)x];
-
-	data->last.xmin = *begin;
-
-#ifdef PLFIT_DEBUG
-	printf("Trying with xmin = %.4f\n", *begin);
-#endif
-
-	plfit_i_estimate_alpha_continuous_sorted(begin, (size_t) (data->end-begin), *begin,
-			&data->last.alpha);
-	plfit_i_ks_test_continuous(begin, data->end, data->last.alpha, *begin,
-			&data->last.D);
-
-	return data->last.D;
-}
-
-int plfit_i_continuous_xmin_opt_progress(void* instance, double x, double fx,
-		double min, double fmin, double left, double right, int k) {
-#ifdef PLFIT_DEBUG
-    printf("Iteration #%d: [%.4f; %.4f), x=%.4f, fx=%.4f, min=%.4f, fmin=%.4f\n",
-            k, left, right, x, fx, min, fmin);
-#endif
-
-	/* Continue only if `left' and `right' point to different integers */
-	return (int)left == (int)right;
-}
-
-int plfit_continuous(double* xs, size_t n, const plfit_continuous_options_t* options,
-        plfit_result_t* result) {
-	gss_parameter_t gss_param;
-	plfit_continuous_xmin_opt_data_t opt_data;
-	plfit_result_t best_result;
-	int success;
-	size_t i, best_n, num_uniques;
-    double x, *px;
-
-    DATA_POINTS_CHECK;
-
-	if (!options)
-		options = &plfit_continuous_default_options;
-
-    /* Make a copy of xs and sort it */
-    opt_data.begin = (double*)malloc(sizeof(double) * n);
-    memcpy(opt_data.begin, xs, sizeof(double) * n);
-    qsort(opt_data.begin, n, sizeof(double), double_comparator);
-    opt_data.end = opt_data.begin + n;
-
-    /* Create an array containing pointers to the unique elements of the input. From
-     * each block of unique elements, we add the pointer to the first one. */
-    opt_data.uniques = unique_element_pointers(opt_data.begin, opt_data.end,
-			&num_uniques);
-    if (opt_data.uniques == 0)
-        return PLFIT_ENOMEM;
-
-    /* We will now determine the best xmin that yields the lowest D-score.
-	 * First we try a golden section search if needed. If that fails, we try
-	 * a linear search.
-     */
-	if (options->xmin_method == PLFIT_GSS_OR_LINEAR && num_uniques > 5) {
-		gss_parameter_init(&gss_param);
-		success = (gss(0, num_uniques-5, &x, 0,
-				plfit_i_continuous_xmin_opt_evaluate,
-				plfit_i_continuous_xmin_opt_progress, &opt_data, &gss_param) == 0);
-		best_result = opt_data.last;
-		/* plfit_i_continuous_xmin_opt_evaluate will set opt_data.last to
-		 * indicate the location of the optimum and the value of D */
-	} else {
-		success = 0;
-	}
-
-	if (success) {
-		/* calculate best_n because we'll need it later. Luckily x indicates
-		 * the index in opt_data.uniques that we have to look up in order to
-		 * find the first element in the array that is included */
-		px = opt_data.uniques[(int)x];
-		best_n = (size_t) (opt_data.end-px+1);
-	} else {
-		/* GSS failed or skipped; try linear search */
-
-		/* Prepare some variables */
-		best_n = 0;
-		best_result.D = DBL_MAX;
-		best_result.xmin = 0;
-		best_result.alpha = 0;
-		
-		for (i = 0; i < num_uniques-1; i++) {
-			plfit_i_continuous_xmin_opt_evaluate(&opt_data, i);
-			if (opt_data.last.D < best_result.D) {
-				best_result = opt_data.last;
-				best_n = (size_t) (opt_data.end - 
-						   opt_data.uniques[i] + 1);
-			}
-		}
-	}
-
-    /* Get rid of the uniques array, we don't need it any more */
-    free(opt_data.uniques);
-
-    /* Sort out the result */
-    *result = best_result;
-    if (options->finite_size_correction)
-        plfit_i_perform_finite_size_correction(result, best_n);
-    result->p = plfit_ks_test_one_sample_p(result->D, best_n);
-    plfit_log_likelihood_continuous(opt_data.begin + n - best_n, best_n,
-			result->alpha, result->xmin, &result->L);
-
-    /* Get rid of the copied data as well */
-    free(opt_data.begin);
-
-    return PLFIT_SUCCESS;
-}
-
-/********** Discrete power law distribution fitting **********/
-
-typedef struct {
-    size_t m;
-    double logsum;
-    double xmin;
-} plfit_i_estimate_alpha_discrete_data_t;
-
-double plfit_i_logsum_discrete(double* begin, double* end, double xmin) {
-    double logsum = 0.0;
-    for (; begin != end; begin++)
-        logsum += log(*begin);
-    return logsum;
-}
-
-void plfit_i_logsum_less_than_discrete(double* begin, double* end, double xmin,
-        double* logsum, size_t* m) {
-    double result = 0.0;
-    size_t count = 0;
-
-    for (; begin != end; begin++) {
-        if (*begin < xmin)
-            continue;
-
-        result += log(*begin);
-        count++;
-    }
-
-    *logsum = result;
-    *m = count;
-}
-
-lbfgsfloatval_t plfit_i_estimate_alpha_discrete_lbfgs_evaluate(
-        void* instance, const lbfgsfloatval_t* x,
-        lbfgsfloatval_t* g, const int n,
-        const lbfgsfloatval_t step) {
-    plfit_i_estimate_alpha_discrete_data_t* data;
-    lbfgsfloatval_t result;
-    double dx = step;
-    double huge = 1e10;     /* pseudo-infinity; apparently DBL_MAX does not work */
-
-    data = (plfit_i_estimate_alpha_discrete_data_t*)instance;
-
-#ifdef PLFIT_DEBUG
-    printf("- Evaluating at %.4f (step = %.4f, xmin = %.4f)\n", *x, step, data->xmin);
-#endif
-
-	if (isnan(*x)) {
-		g[0] = huge;
-		return huge;
-	}
-
-    /* Find the delta X value to estimate the gradient */
-    if (dx > 0.001 || dx == 0)
-        dx = 0.001;
-    else if (dx < -0.001)
-        dx = -0.001;
-
-	/* Is x[0] in its valid range? */
-	if (x[0] <= 1.0) {
-		/* The Hurwitz zeta function is infinite in this case */
-        g[0] = (dx > 0) ? -huge : huge;
-		return huge;
-	}
-	if (x[0] + dx <= 1.0)
-		g[0] = huge;
-	else
-		g[0] = data->logsum + data->m *
-			(log(gsl_sf_hzeta(x[0] + dx, data->xmin)) - log(gsl_sf_hzeta(x[0], data->xmin))) / dx;
-
-    result = x[0] * data->logsum + data->m * log(gsl_sf_hzeta(x[0], data->xmin));
-
-#ifdef PLFIT_DEBUG
-    printf("  - Gradient: %.4f\n", g[0]);
-    printf("  - Result: %.4f\n", result);
-#endif
-
-    return result;
-}
-
-int plfit_i_estimate_alpha_discrete_lbfgs_progress(void* instance,
-        const lbfgsfloatval_t* x, const lbfgsfloatval_t* g,
-        const lbfgsfloatval_t fx, const lbfgsfloatval_t xnorm,
-        const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step,
-        int n, int k, int ls) {
-    return 0;
-}
-
-int plfit_i_estimate_alpha_discrete_linear_scan(double* xs, size_t n, double xmin,
-        double* alpha, const plfit_discrete_options_t* options,
-		plfit_bool_t sorted) {
-    double curr_alpha, best_alpha, L, L_max;
-    double logsum;
-    size_t m;
-
-    XMIN_CHECK_ONE;
-	if (options->alpha.min <= 1.0) {
-		PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
-	}
-	if (options->alpha.max < options->alpha.min) {
-		PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
-	}
-	if (options->alpha.step <= 0) {
-		PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
-	}
-
-    if (sorted) {
-        logsum = plfit_i_logsum_discrete(xs, xs+n, xmin);
-        m = n;
-    } else {
-        plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &logsum, &m);
-    }
-
-    best_alpha = options->alpha.min; L_max = -DBL_MAX;
-    for (curr_alpha = options->alpha.min; curr_alpha <= options->alpha.max;
-			curr_alpha += options->alpha.step) {
-        L = -curr_alpha * logsum - m * log(gsl_sf_hzeta(curr_alpha, xmin));
-        if (L > L_max) {
-            L_max = L;
-            best_alpha = curr_alpha;
-        }
-    }
-
-    *alpha = best_alpha;
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_i_estimate_alpha_discrete_lbfgs(double* xs, size_t n, double xmin,
-		double* alpha, const plfit_discrete_options_t* options, plfit_bool_t sorted) {
-    lbfgs_parameter_t param;
-    lbfgsfloatval_t* variables;
-    plfit_i_estimate_alpha_discrete_data_t data;
-    int ret;
-
-    XMIN_CHECK_ONE;
-
-    /* Initialize algorithm parameters */
-    lbfgs_parameter_init(&param);
-    param.max_iterations = 0;   /* proceed until infinity */
-
-    /* Set up context for optimization */
-    data.xmin = xmin;
-    if (sorted) {
-        data.logsum = plfit_i_logsum_discrete(xs, xs+n, xmin);
-        data.m = n;
-    } else {
-        plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &data.logsum, &data.m);
-    }
-
-    /* Allocate space for the single alpha variable */
-    variables = lbfgs_malloc(1);
-    variables[0] = 3.0;       /* initial guess */
-
-    /* Optimization */
-    ret = lbfgs(1, variables, /* ptr_fx = */ 0,
-            plfit_i_estimate_alpha_discrete_lbfgs_evaluate,
-            plfit_i_estimate_alpha_discrete_lbfgs_progress,
-            &data, &param);
-
-    if (ret < 0 &&
-        ret != LBFGSERR_ROUNDING_ERROR &&
-        ret != LBFGSERR_MAXIMUMLINESEARCH &&
-        ret != LBFGSERR_CANCELED) {
-        char buf[4096];
-        snprintf(buf, 4096, "L-BFGS optimization signaled an error (error code = %d)", ret);
-        lbfgs_free(variables);
-        PLFIT_ERROR(buf, PLFIT_FAILURE);
-    }
-    *alpha = variables[0];
-    
-    /* Deallocate the variable array */
-    lbfgs_free(variables);
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_i_estimate_alpha_discrete_fast(double* xs, size_t n, double xmin,
-        double* alpha, const plfit_discrete_options_t* options, plfit_bool_t sorted) {
-	plfit_continuous_options_t cont_options;
-
-	if (!options)
-		options = &plfit_discrete_default_options;
-
-	plfit_continuous_options_init(&cont_options);
-	cont_options.finite_size_correction = options->finite_size_correction;
-
-    XMIN_CHECK_ONE;
-
-	if (sorted) {
-		return plfit_i_estimate_alpha_continuous_sorted(xs, n, xmin-0.5, alpha);
-	} else {
-		return plfit_i_estimate_alpha_continuous(xs, n, xmin-0.5, alpha);
-	}
-}
-
-int plfit_i_estimate_alpha_discrete(double* xs, size_t n, double xmin,
-		double* alpha, const plfit_discrete_options_t* options,
-		plfit_bool_t sorted) {
-	switch (options->alpha_method) {
-		case PLFIT_LBFGS:
-			PLFIT_CHECK(plfit_i_estimate_alpha_discrete_lbfgs(xs, n, xmin, alpha,
-						options, sorted));
-			break;
-
-		case PLFIT_LINEAR_SCAN:
-			PLFIT_CHECK(plfit_i_estimate_alpha_discrete_linear_scan(xs, n, xmin,
-						alpha, options, sorted));
-			break;
-
-		case PLFIT_PRETEND_CONTINUOUS:
-			PLFIT_CHECK(plfit_i_estimate_alpha_discrete_fast(xs, n, xmin,
-						alpha, options, sorted));
-			break;
-
-		default:
-			PLFIT_ERROR("unknown optimization method specified", PLFIT_EINVAL);
-	}
-
-	return PLFIT_SUCCESS;
-}
-
-static int plfit_i_ks_test_discrete(double* xs, double* xs_end, const double alpha,
-        const double xmin, double* D) {
-    /* Assumption: xs is sorted and cut off at xmin so the first element is
-     * always larger than or equal to xmin. */
-    double result = 0, n, hzeta, x;
-    int m = 0;
-
-    n = xs_end - xs;
-    hzeta = gsl_sf_hzeta(alpha, xmin);
-
-    while (xs < xs_end) {
-        double d;
-
-        x = *xs;
-        d = fabs(1-(gsl_sf_hzeta(alpha, x) / hzeta) - m / n);
-
-        if (d > result)
-            result = d;
-
-        do {
-            xs++; m++;
-        } while (xs < xs_end && *xs == x);
-    }
-
-    *D = result;
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_log_likelihood_discrete(double* xs, size_t n, double alpha, double xmin, double* L) {
-    double result;
-    size_t m;
-
-    if (alpha <= 1) {
-        PLFIT_ERROR("alpha must be greater than one", PLFIT_EINVAL);
-    }
-    XMIN_CHECK_ONE;
-
-    plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &result, &m);
-    result = - alpha * result - m * log(gsl_sf_hzeta(alpha, xmin));
-
-    *L = result;
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_estimate_alpha_discrete(double* xs, size_t n, double xmin,
-        const plfit_discrete_options_t* options, plfit_result_t *result) {
-    double *xs_copy, *end;
-
-	if (!options)
-		options = &plfit_discrete_default_options;
-
-	/* Check the validity of the input parameters */
-    DATA_POINTS_CHECK;
-	if (options->alpha_method == PLFIT_LINEAR_SCAN) {
-		if (options->alpha.min <= 1.0) {
-			PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
-		}
-		if (options->alpha.max < options->alpha.min) {
-			PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
-		}
-		if (options->alpha.step <= 0) {
-			PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
-		}
-	}
-
-    /* Make a copy of xs and sort it */
-    xs_copy = (double*)malloc(sizeof(double) * n);
-    memcpy(xs_copy, xs, sizeof(double) * n);
-    qsort(xs_copy, n, sizeof(double), double_comparator);
-
-    xs = xs_copy; end = xs_copy + n;
-    while (xs < end && *xs < xmin)
-        xs++;
-    n = (size_t) (end - xs);
-
-    PLFIT_CHECK(plfit_i_estimate_alpha_discrete(xs, n, xmin, &result->alpha,
-				options, /* sorted = */ 1));
-    PLFIT_CHECK(plfit_i_ks_test_discrete(xs, end, result->alpha, xmin, &result->D));
-
-    result->xmin = xmin;
-    if (options->finite_size_correction)
-        plfit_i_perform_finite_size_correction(result, n);
-    result->p = plfit_ks_test_one_sample_p(result->D, n);
-    plfit_log_likelihood_discrete(xs, n, result->alpha, result->xmin, &result->L);
-
-    free(xs_copy);
-
-    return PLFIT_SUCCESS;
-}
-
-int plfit_discrete(double* xs, size_t n, const plfit_discrete_options_t* options,
-        plfit_result_t* result) {
-    double curr_D, curr_alpha;
-    plfit_result_t best_result;
-    double *xs_copy, *px, *end, *end_xmin, prev_x;
-	size_t best_n;
-    size_t m;
-
-	if (!options)
-		options = &plfit_discrete_default_options;
-
-	/* Check the validity of the input parameters */
-    DATA_POINTS_CHECK;
-	if (options->alpha_method == PLFIT_LINEAR_SCAN) {
-		if (options->alpha.min <= 1.0) {
-			PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
-		}
-		if (options->alpha.max < options->alpha.min) {
-			PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
-		}
-		if (options->alpha.step <= 0) {
-			PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
-		}
-	}
-
-    /* Make a copy of xs and sort it */
-    xs_copy = (double*)malloc(sizeof(double) * n);
-    memcpy(xs_copy, xs, sizeof(double) * n);
-    qsort(xs_copy, n, sizeof(double), double_comparator);
-
-    best_result.D = DBL_MAX;
-    best_result.xmin = 1;
-    best_result.alpha = 1;
-	best_n = 0;
-
-    /* Make sure there are at least three distinct values if possible */
-    px = xs_copy; end = px + n; end_xmin = end - 1; m = 0;
-    prev_x = *end_xmin;
-    while (*end_xmin == prev_x && end_xmin > px)
-        end_xmin--;
-    prev_x = *end_xmin;
-    while (*end_xmin == prev_x && end_xmin > px)
-        end_xmin--;
-
-    prev_x = 0;
-    while (px < end_xmin) {
-        while (px < end_xmin && *px == prev_x) {
-            px++; m++;
-        }
-
-	plfit_i_estimate_alpha_discrete(px, n - m, *px,
-					&curr_alpha, options, /* sorted = */ 1);
-        plfit_i_ks_test_discrete(px, end, curr_alpha, *px, &curr_D);
-
-        if (curr_D < best_result.D) {
-            best_result.alpha = curr_alpha;
-            best_result.xmin = *px;
-            best_result.D = curr_D;
-	    best_n = n - m;
-        }
-
-        prev_x = *px;
-        px++; m++;
-    }
-
-    *result = best_result;
-    if (options->finite_size_correction)
-        plfit_i_perform_finite_size_correction(result, best_n);
-    result->p = plfit_ks_test_one_sample_p(result->D, best_n);
-    plfit_log_likelihood_discrete(xs_copy+(n-best_n), best_n,
-			result->alpha, result->xmin, &result->L);
-
-    free(xs_copy);
-
-    return PLFIT_SUCCESS;
-}
-
+/* vim:set ts=4 sw=4 sts=4 et: */
+/* plfit.c
+ *
+ * Copyright (C) 2010-2011 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+#include "gss.h"
+#include "lbfgs.h"
+#include "platform.h"
+#include "plfit.h"
+#include "kolmogorov.h"
+#include "sampling.h"
+#include "hzeta.h"
+
+/* #define PLFIT_DEBUG */
+
+#define DATA_POINTS_CHECK \
+    if (n <= 0) { \
+        PLFIT_ERROR("no data points", PLFIT_EINVAL); \
+    }
+
+#define XMIN_CHECK_ZERO \
+    if (xmin <= 0) { \
+        PLFIT_ERROR("xmin must be greater than zero", PLFIT_EINVAL); \
+    }
+#define XMIN_CHECK_ONE \
+    if (xmin < 1) { \
+        PLFIT_ERROR("xmin must be at least 1", PLFIT_EINVAL); \
+    }
+
+static int plfit_i_resample_continuous(double* xs_head, size_t num_smaller,
+        size_t n, double alpha, double xmin, size_t num_samples, mt_rng_t* rng,
+        double* result);
+static int plfit_i_resample_discrete(double* xs_head, size_t num_smaller,
+        size_t n, double alpha, double xmin, size_t num_samples, mt_rng_t* rng,
+        double* result);
+
+static int double_comparator(const void *a, const void *b) {
+    const double *da = (const double*)a;
+    const double *db = (const double*)b;
+    return (*da > *db) - (*da < *db);
+}
+
+static int plfit_i_copy_and_sort(double* xs, size_t n, double** result) {
+    *result = (double*)malloc(sizeof(double) * n);
+    if (*result == 0) {
+        PLFIT_ERROR("cannot create sorted copy of input data", PLFIT_ENOMEM);
+    }
+
+    memcpy(*result, xs, sizeof(double) * n);
+    qsort(*result, n, sizeof(double), double_comparator);
+
+    return PLFIT_SUCCESS;
+}
+
+/**
+ * Given an unsorted array of doubles, counts how many elements there are that
+ * are smaller than a given value.
+ *
+ * \param  begin          pointer to the beginning of the array
+ * \param  end            pointer to the first element after the end of the array
+ * \param  xmin           the threshold value
+ *
+ * \return the nubmer of elements in the array that are smaller than the given
+ *         value.
+ */
+static size_t count_smaller(double* begin, double* end, double xmin) {
+    double* p;
+    size_t counter = 0;
+
+    for (p = begin; p < end; p++) {
+        if (*p < xmin) {
+            counter++;
+        }
+    }
+
+    return counter;
+}
+
+/**
+ * Given an unsorted array of doubles, return another array that contains the
+ * elements that are smaller than a given value
+ *
+ * \param  begin          pointer to the beginning of the array
+ * \param  end            pointer to the first element after the end of the array
+ * \param  xmin           the threshold value
+ * \param  result_length  if not \c NULL, the number of unique elements in the
+ *                        given array is returned here
+ *
+ * \return pointer to the head of the new array or 0 if there is not enough
+ * memory
+ */
+static double* extract_smaller(double* begin, double* end, double xmin,
+        size_t* result_length) {
+    size_t counter = count_smaller(begin, end, xmin);
+    double *p, *result;
+
+    result = calloc(counter, sizeof(double));
+    if (result == 0)
+        return 0;
+
+    for (p = result; begin < end; begin++) {
+        if (*begin < xmin) {
+            *p = *begin;
+            p++;
+        }
+    }
+
+    if (result_length) {
+        *result_length = counter;
+    }
+
+    return result;
+}
+
+/**
+ * Given a sorted array of doubles, return another array that contains pointers
+ * into the array for the start of each block of identical elements.
+ *
+ * \param  begin          pointer to the beginning of the array
+ * \param  end            pointer to the first element after the end of the array
+ * \param  result_length  if not \c NULL, the number of unique elements in the
+ *                        given array is returned here
+ *
+ * \return pointer to the head of the new array or 0 if there is not enough
+ * memory
+ */
+static double** unique_element_pointers(double* begin, double* end, size_t* result_length) {
+    double* ptr = begin;
+    double** result;
+    double prev_x;
+    size_t num_elts = 15;
+    size_t used_elts = 0;
+
+    /* Special case: empty array */
+    if (begin == end) {
+        result = calloc(1, sizeof(double*));
+        if (result != 0) {
+            result[0] = 0;
+        }
+        return result;
+    }
+
+    /* Allocate initial result array, including the guard element */
+    result = calloc(num_elts+1, sizeof(double*));
+    if (result == 0)
+        return 0;
+
+    prev_x = *begin;
+    result[used_elts++] = begin;
+
+    /* Process the input array */
+    for (ptr = begin+1; ptr < end; ptr++) {
+        if (*ptr == prev_x)
+            continue;
+
+        /* New block found */
+        if (used_elts >= num_elts) {
+            /* Array full; allocate a new chunk */
+            num_elts = num_elts*2 + 1;
+            result = realloc(result, sizeof(double*) * (num_elts+1));
+            if (result == 0)
+                return 0;
+        }
+
+        /* Store the new element */
+        result[used_elts++] = ptr;
+        prev_x = *ptr;
+    }
+
+    /* Calculate the result length */
+    if (result_length != 0) {
+        *result_length = used_elts;
+    }
+
+    /* Add the guard entry to the end of the result */
+    result[used_elts++] = 0;
+
+    return result;
+}
+
+static void plfit_i_perform_finite_size_correction(plfit_result_t* result, size_t n) {
+    result->alpha = result->alpha * (n-1) / n + 1.0 / n;
+}
+
+/********** Continuous power law distribution fitting **********/
+
+static void plfit_i_logsum_less_than_continuous(double* begin, double* end,
+        double xmin, double* result, size_t* m) {
+    double logsum = 0.0;
+    size_t count = 0;
+
+    for (; begin != end; begin++) {
+        if (*begin >= xmin) {
+            count++;
+            logsum += log(*begin / xmin);
+        }
+    }
+
+    *m = count;
+    *result = logsum;
+}
+
+static double plfit_i_logsum_continuous(double* begin, double* end, double xmin) {
+    double logsum = 0.0;
+    for (; begin != end; begin++)
+        logsum += log(*begin / xmin);
+    return logsum;
+}
+
+static int plfit_i_estimate_alpha_continuous(double* xs, size_t n,
+        double xmin, double* alpha) {
+    double result;
+    size_t m;
+
+    XMIN_CHECK_ZERO;
+
+    plfit_i_logsum_less_than_continuous(xs, xs+n, xmin, &result, &m);
+
+    if (m == 0) {
+        PLFIT_ERROR("no data point was larger than xmin", PLFIT_EINVAL);
+    }
+
+    *alpha = 1 + m / result;
+
+    return PLFIT_SUCCESS;
+}
+
+static int plfit_i_estimate_alpha_continuous_sorted(double* xs, size_t n,
+        double xmin, double* alpha) {
+    double* end = xs+n;
+
+    XMIN_CHECK_ZERO;
+
+    for (; xs != end && *xs < xmin; xs++);
+    if (xs == end) {
+        PLFIT_ERROR("no data point was larger than xmin", PLFIT_EINVAL);
+    }
+
+    *alpha = 1 + (end-xs) / plfit_i_logsum_continuous(xs, end, xmin);
+
+    return PLFIT_SUCCESS;
+}
+
+static int plfit_i_ks_test_continuous(double* xs, double* xs_end,
+        const double alpha, const double xmin, double* D) {
+    /* Assumption: xs is sorted and cut off at xmin so the first element is
+     * always larger than or equal to xmin. */
+    double result = 0, n;
+    int m = 0;
+
+    n = xs_end - xs;
+
+    while (xs < xs_end) {
+        double d = fabs(1-pow(xmin / *xs, alpha-1) - m / n);
+
+        if (d > result)
+            result = d;
+
+        xs++; m++;
+    }
+
+    *D = result;
+
+    return PLFIT_SUCCESS;
+}
+
+static int plfit_i_calculate_p_value_continuous(double* xs, size_t n,
+        const plfit_continuous_options_t *options, plfit_bool_t xmin_fixed,
+        plfit_result_t *result) {
+    long int num_trials;
+    long int successes = 0;
+    double *xs_head;
+    size_t num_smaller;
+    plfit_continuous_options_t options_no_p_value = *options;
+    int retval = PLFIT_SUCCESS;
+
+    if (options->p_value_method == PLFIT_P_VALUE_SKIP) {
+        result->p = NAN;
+        return PLFIT_SUCCESS;
+    }
+
+    if (options->p_value_method == PLFIT_P_VALUE_APPROXIMATE) {
+        num_smaller = count_smaller(xs, xs + n, result->xmin);
+        result->p = plfit_ks_test_one_sample_p(result->D, n - num_smaller);
+        return PLFIT_SUCCESS;
+    }
+
+    options_no_p_value.p_value_method = PLFIT_P_VALUE_SKIP;
+    num_trials = (long int)(0.25 / options->p_value_precision / options->p_value_precision);
+    if (num_trials <= 0) {
+        PLFIT_ERROR("invalid p-value precision", PLFIT_EINVAL);
+    }
+
+    /* Extract the head of xs that contains elements smaller than xmin */
+    xs_head = extract_smaller(xs, xs+n, result->xmin, &num_smaller);
+    if (xs_head == 0)
+        PLFIT_ERROR("cannot calculate exact p-value", PLFIT_ENOMEM);
+
+#ifdef _OPENMP
+#pragma omp parallel
+#endif
+    {
+        /* Parallel section starts here. If we are compiling using OpenMP, each
+         * thread will use its own RNG that is seeded from the master RNG. If
+         * we are compiling without OpenMP, there is only one thread and it uses
+         * the master RNG. This section must be critical to ensure that only one
+         * thread is using the master RNG at the same time. */
+#ifdef _OPENMP
+        mt_rng_t private_rng;
+#endif
+        mt_rng_t *p_rng;
+        double *ys;
+        long int i;
+        plfit_result_t result_synthetic;
+
+#ifdef _OPENMP
+#pragma omp critical
+        {
+            p_rng = &private_rng;
+            mt_init_from_rng(p_rng, options->rng);
+        }
+#else
+        p_rng = options->rng;
+#endif
+
+        /* Allocate memory to sample into */
+        ys = calloc(n, sizeof(double));
+        if (ys == 0) {
+            retval = PLFIT_ENOMEM;
+        } else {
+            /* The main for loop starts here. */
+#ifdef _OPENMP
+#pragma omp for reduction(+:successes)
+#endif
+            for (i = 0; i < num_trials; i++) {
+                plfit_i_resample_continuous(xs_head, num_smaller, n, result->alpha,
+                        result->xmin, n, p_rng, ys);
+                if (xmin_fixed) {
+                    plfit_estimate_alpha_continuous(ys, n, result->xmin,
+                                &options_no_p_value, &result_synthetic);
+                } else {
+                    plfit_continuous(ys, n, &options_no_p_value, &result_synthetic);
+                }
+                if (result_synthetic.D > result->D)
+                    successes++;
+            }
+            free(ys);
+        }
+
+        /* End of parallelized part */
+    }
+
+    free(xs_head);
+
+    if (retval == PLFIT_SUCCESS) {
+        result->p = successes / ((double)num_trials);
+    } else {
+        PLFIT_ERROR("cannot calculate exact p-value", retval);
+    }
+
+    return retval;
+}
+
+int plfit_log_likelihood_continuous(double* xs, size_t n, double alpha,
+        double xmin, double* L) {
+    double logsum, c;
+    size_t m;
+
+    if (alpha <= 1) {
+        PLFIT_ERROR("alpha must be greater than one", PLFIT_EINVAL);
+    }
+    XMIN_CHECK_ZERO;
+
+    c = (alpha - 1) / xmin;
+    plfit_i_logsum_less_than_continuous(xs, xs+n, xmin, &logsum, &m);
+    *L = -alpha * logsum + log(c) * m;
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_estimate_alpha_continuous_sorted(double* xs, size_t n, double xmin,
+        const plfit_continuous_options_t* options, plfit_result_t *result) {
+    double *begin, *end;
+
+    if (!options)
+        options = &plfit_continuous_default_options;
+
+    begin = xs;
+    end = xs + n;
+    while (begin < end && *begin < xmin)
+        begin++;
+
+    PLFIT_CHECK(plfit_i_estimate_alpha_continuous_sorted(begin, end-begin,
+                xmin, &result->alpha));
+    PLFIT_CHECK(plfit_i_ks_test_continuous(begin, end, result->alpha,
+                xmin, &result->D));
+
+    if (options->finite_size_correction)
+        plfit_i_perform_finite_size_correction(result, end-begin);
+    result->xmin = xmin;
+
+    PLFIT_CHECK(plfit_log_likelihood_continuous(begin, end-begin, result->alpha,
+                result->xmin, &result->L));
+    PLFIT_CHECK(plfit_i_calculate_p_value_continuous(xs, n, options, 1, result));
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_estimate_alpha_continuous(double* xs, size_t n, double xmin,
+        const plfit_continuous_options_t* options, plfit_result_t *result) {
+    double *xs_copy;
+
+    if (!options)
+        options = &plfit_continuous_default_options;
+
+    PLFIT_CHECK(plfit_i_copy_and_sort(xs, n, &xs_copy));
+    PLFIT_CHECK(plfit_estimate_alpha_continuous_sorted(xs_copy, n, xmin,
+                options, result));
+    free(xs_copy);
+
+    return PLFIT_SUCCESS;
+}
+
+typedef struct {
+    double *begin;        /**< Pointer to the beginning of the array holding the data */
+    double *end;          /**< Pointer to after the end of the array holding the data */
+    double **probes;      /**< Pointers to the elements of the array that will be probed */
+    size_t num_probes;    /**< Number of probes */
+    plfit_result_t last;  /**< Result of the last evaluation */
+} plfit_continuous_xmin_opt_data_t;
+
+static double plfit_i_continuous_xmin_opt_evaluate(void* instance, double x) {
+    plfit_continuous_xmin_opt_data_t* data = (plfit_continuous_xmin_opt_data_t*)instance;
+    double* begin = data->probes[(long int)x];
+
+    data->last.xmin = *begin;
+
+#ifdef PLFIT_DEBUG
+    printf("Trying with probes[%ld] = %.4f\n", (long int)x, *begin);
+#endif
+
+    plfit_i_estimate_alpha_continuous_sorted(begin, data->end-begin, *begin,
+            &data->last.alpha);
+    plfit_i_ks_test_continuous(begin, data->end, data->last.alpha, *begin,
+            &data->last.D);
+
+    return data->last.D;
+}
+
+static int plfit_i_continuous_xmin_opt_progress(void* instance, double x, double fx,
+        double min, double fmin, double left, double right, int k) {
+#ifdef PLFIT_DEBUG
+    printf("Iteration #%d: [%.4f; %.4f), x=%.4f, fx=%.4f, min=%.4f, fmin=%.4f\n",
+            k, left, right, x, fx, min, fmin);
+#endif
+
+    /* Continue only if `left' and `right' point to different integers */
+    return (int)left == (int)right;
+}
+
+static int plfit_i_continuous_xmin_opt_linear_scan(
+        plfit_continuous_xmin_opt_data_t* opt_data, plfit_result_t* best_result,
+        size_t* best_n) {
+    size_t i;
+    plfit_result_t global_best_result;
+    size_t global_best_n;
+
+    /* Prepare some variables */
+    global_best_n = 0;
+    global_best_result.D = DBL_MAX;
+    global_best_result.xmin = 0;
+    global_best_result.alpha = 0;
+
+    /* Due to the OpenMP parallelization, we do things as follows. Each
+     * OpenMP thread will search for the best D-score on its own and store
+     * the result in a private local_best_result variable. The end of the
+     * parallel block contains a critical section that threads will enter
+     * one by one and compare their private local_best_result with a
+     * global_best that is shared among the threads.
+     */
+#ifdef _OPENMP
+#pragma omp parallel shared(global_best_result, global_best_n) private(i) firstprivate(opt_data)
+#endif
+    {
+        /* These variables are private since they are declared within the
+         * parallel block */
+        plfit_result_t local_best_result;
+        plfit_continuous_xmin_opt_data_t local_opt_data = *opt_data;
+        size_t local_best_n;
+
+        /* Initialize the local_best_result and local_best_n variables */
+        local_best_n = 0;
+        local_best_result.D = DBL_MAX;
+        local_best_result.xmin = 0;
+        local_best_result.alpha = 0;
+
+        /* The range of the for loop below is divided among the threads.
+         * nowait means that there will be no implicit barrier at the end
+         * of the loop so threads that get there earlier can enter the
+         * critical section without waiting for the others */
+#ifdef _OPENMP
+#pragma omp for nowait schedule(dynamic,10)
+#endif
+        for (i = 0; i < local_opt_data.num_probes-1; i++) {
+            plfit_i_continuous_xmin_opt_evaluate(&local_opt_data, i);
+            if (local_opt_data.last.D < local_best_result.D) {
+#ifdef PLFIT_DEBUG
+                printf("Found new local best at %g with D=%g\n",
+                        local_opt_data.last.xmin, local_opt_data.last.D);
+#endif
+                local_best_result = local_opt_data.last;
+                local_best_n = local_opt_data.end - local_opt_data.probes[i] + 1;
+            }
+        }
+
+        /* Critical section that finds the global best result from the
+         * local ones collected by each thread */
+#ifdef _OPENMP
+#pragma omp critical
+#endif
+        if (local_best_result.D < global_best_result.D) {
+            global_best_result = local_best_result;
+            global_best_n = local_best_n;
+#ifdef PLFIT_DEBUG
+            printf("Found new global best at %g with D=%g\n", global_best_result.xmin,
+                    global_best_result.D);
+#endif
+        }
+    }
+
+    *best_result = global_best_result;
+    *best_n = global_best_n;
+
+#ifdef PLFIT_DEBUG
+    printf("Returning global best: %g\n", best_result->xmin);
+#endif
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_continuous(double* xs, size_t n, const plfit_continuous_options_t* options,
+        plfit_result_t* result) {
+    gss_parameter_t gss_param;
+    plfit_continuous_xmin_opt_data_t opt_data;
+    plfit_result_t best_result = {
+        /* alpha = */ NAN,
+        /* xmin = */ NAN,
+        /* L = */ NAN,
+        /* D = */ NAN,
+        /* p = */ NAN
+    };
+
+    int success;
+    size_t i, best_n, num_uniques;
+    double x, *px, **uniques;
+
+    DATA_POINTS_CHECK;
+
+    /* Sane defaults */
+    best_n = n;
+    if (!options)
+        options = &plfit_continuous_default_options;
+
+    /* Make a copy of xs and sort it */
+    PLFIT_CHECK(plfit_i_copy_and_sort(xs, n, &opt_data.begin));
+    opt_data.end = opt_data.begin + n;
+
+    /* Create an array containing pointers to the unique elements of the input. From
+     * each block of unique elements, we add the pointer to the first one. */
+    uniques = unique_element_pointers(opt_data.begin, opt_data.end, &num_uniques);
+    if (uniques == 0)
+        PLFIT_ERROR("cannot fit continuous power-law", PLFIT_ENOMEM);
+
+    /* We will now determine the best xmin that yields the lowest D-score. The
+     * 'success' variable will denote whether the search procedure we tried was
+     * successful. If it is false after having exhausted all options, we fall
+     * back to a linear search. */
+    success = 0;
+    switch (options->xmin_method) {
+        case PLFIT_GSS_OR_LINEAR:
+            /* Try golden section search first. */
+            if (num_uniques > 5) {
+                opt_data.probes = uniques;
+                opt_data.num_probes = num_uniques;
+                gss_parameter_init(&gss_param);
+                success = (gss(0, opt_data.num_probes-5, &x, 0,
+                        plfit_i_continuous_xmin_opt_evaluate,
+                        plfit_i_continuous_xmin_opt_progress, &opt_data, &gss_param) == 0);
+                if (success) {
+                    px = opt_data.probes[(int)x];
+                    best_n = opt_data.end-px+1;
+                    best_result = opt_data.last;
+                }
+            }
+            break;
+
+        case PLFIT_STRATIFIED_SAMPLING:
+            if (num_uniques >= 50) {
+                /* Try stratified sampling to narrow down the interval where the minimum
+                 * is likely to reside. We check 10% of the unique items, distributed
+                 * evenly, find the one with the lowest D-score, and then check the
+                 * area around it more thoroughly. */
+                const size_t subdivision_length = 10;
+                size_t num_strata = num_uniques / subdivision_length;
+                double **strata = calloc(num_strata, sizeof(double*));
+
+                for (i = 0; i < num_strata; i++) {
+                    strata[i] = uniques[i * subdivision_length];
+                }
+
+                opt_data.probes = strata;
+                opt_data.num_probes = num_strata;
+                plfit_i_continuous_xmin_opt_linear_scan(&opt_data, &best_result, &best_n);
+
+                opt_data.num_probes = 0;
+                for (i = 0; i < num_strata; i++) {
+                    if (*strata[i] == best_result.xmin) {
+                        /* Okay, scan more thoroughly from strata[i-1] to strata[i+1],
+                         * which is from uniques[(i-1)*subdivision_length] to
+                         * uniques[(i+1)*subdivision_length */
+                        opt_data.probes = uniques + (i > 0 ? (i-1)*subdivision_length : 0);
+                        opt_data.num_probes = 0;
+                        if (i != 0)
+                            opt_data.num_probes += subdivision_length;
+                        if (i != num_strata-1)
+                            opt_data.num_probes += subdivision_length;
+                        break;
+                    }
+                }
+
+                free(strata);
+                if (opt_data.num_probes > 0) {
+                    /* Do a strict linear scan in the subrange determined above */
+                    plfit_i_continuous_xmin_opt_linear_scan(&opt_data,
+                            &best_result, &best_n);
+                    success = 1;
+                } else {
+                    /* This should not happen, but we handle it anyway */
+                    success = 0;
+                }
+            }
+            break;
+
+        default:
+            /* Just use the linear search */
+            break;
+    }
+
+    if (!success) {
+        /* More advanced search methods failed or were skipped; try linear search */
+        opt_data.probes = uniques;
+        opt_data.num_probes = num_uniques;
+        plfit_i_continuous_xmin_opt_linear_scan(&opt_data, &best_result, &best_n);
+        success = 1;
+    }
+
+    /* Get rid of the uniques array, we don't need it any more */
+    free(uniques);
+
+    /* Sort out the result */
+    *result = best_result;
+    if (options->finite_size_correction)
+        plfit_i_perform_finite_size_correction(result, best_n);
+
+    PLFIT_CHECK(plfit_log_likelihood_continuous(opt_data.begin + n - best_n, best_n,
+            result->alpha, result->xmin, &result->L));
+    PLFIT_CHECK(plfit_i_calculate_p_value_continuous(opt_data.begin, n, options, 0, result));
+
+    /* Get rid of the copied data as well */
+    free(opt_data.begin);
+
+    return PLFIT_SUCCESS;
+}
+
+/********** Discrete power law distribution fitting **********/
+
+typedef struct {
+    size_t m;
+    double logsum;
+    double xmin;
+} plfit_i_estimate_alpha_discrete_data_t;
+
+static double plfit_i_logsum_discrete(double* begin, double* end, double xmin) {
+    double logsum = 0.0;
+    for (; begin != end; begin++)
+        logsum += log(*begin);
+    return logsum;
+}
+
+static void plfit_i_logsum_less_than_discrete(double* begin, double* end, double xmin,
+        double* logsum, size_t* m) {
+    double result = 0.0;
+    size_t count = 0;
+
+    for (; begin != end; begin++) {
+        if (*begin < xmin)
+            continue;
+
+        result += log(*begin);
+        count++;
+    }
+
+    *logsum = result;
+    *m = count;
+}
+
+static lbfgsfloatval_t plfit_i_estimate_alpha_discrete_lbfgs_evaluate(
+        void* instance, const lbfgsfloatval_t* x,
+        lbfgsfloatval_t* g, const int n,
+        const lbfgsfloatval_t step) {
+    plfit_i_estimate_alpha_discrete_data_t* data;
+    lbfgsfloatval_t result;
+    double dx = step;
+    double huge = 1e10;     /* pseudo-infinity; apparently DBL_MAX does not work */
+    double lnhzeta_x=NAN;
+    double lnhzeta_deriv_x=NAN;
+
+    data = (plfit_i_estimate_alpha_discrete_data_t*)instance;
+
+#ifdef PLFIT_DEBUG
+    printf("- Evaluating at %.4f (step = %.4f, xmin = %.4f)\n", *x, step, data->xmin);
+#endif
+
+    if (isnan(*x)) {
+        g[0] = huge;
+        return huge;
+    }
+
+    /* Find the delta X value to estimate the gradient */
+    if (dx > 0.001 || dx == 0)
+        dx = 0.001;
+    else if (dx < -0.001)
+        dx = -0.001;
+
+    /* Is x[0] in its valid range? */
+    if (x[0] <= 1.0) {
+        /* The Hurwitz zeta function is infinite in this case */
+        g[0] = (dx > 0) ? -huge : huge;
+        return huge;
+    }
+    if (x[0] + dx <= 1.0) {
+        g[0] = huge;
+        result = x[0] * data->logsum + data->m * hsl_sf_lnhzeta(x[0], data->xmin);
+    } else {
+        hsl_sf_lnhzeta_deriv_tuple(x[0], data->xmin, &lnhzeta_x, &lnhzeta_deriv_x);
+        g[0] = data->logsum + data->m * lnhzeta_deriv_x;
+        result = x[0] * data->logsum + data->m * lnhzeta_x;
+    }
+
+#ifdef PLFIT_DEBUG
+    printf("  - Gradient: %.4f\n", g[0]);
+    printf("  - Result: %.4f\n", result);
+#endif
+
+    return result;
+}
+
+static int plfit_i_estimate_alpha_discrete_lbfgs_progress(void* instance,
+        const lbfgsfloatval_t* x, const lbfgsfloatval_t* g,
+        const lbfgsfloatval_t fx, const lbfgsfloatval_t xnorm,
+        const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step,
+        int n, int k, int ls) {
+    return 0;
+}
+
+static int plfit_i_estimate_alpha_discrete_linear_scan(double* xs, size_t n,
+        double xmin, double* alpha, const plfit_discrete_options_t* options,
+        plfit_bool_t sorted) {
+    double curr_alpha, best_alpha, L, L_max;
+    double logsum;
+    size_t m;
+
+    XMIN_CHECK_ONE;
+    if (options->alpha.min <= 1.0) {
+        PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
+    }
+    if (options->alpha.max < options->alpha.min) {
+        PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
+    }
+    if (options->alpha.step <= 0) {
+        PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
+    }
+
+    if (sorted) {
+        logsum = plfit_i_logsum_discrete(xs, xs+n, xmin);
+        m = n;
+    } else {
+        plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &logsum, &m);
+    }
+
+    best_alpha = options->alpha.min; L_max = -DBL_MAX;
+    for (curr_alpha = options->alpha.min; curr_alpha <= options->alpha.max;
+            curr_alpha += options->alpha.step) {
+        L = -curr_alpha * logsum - m * hsl_sf_lnhzeta(curr_alpha, xmin);
+        if (L > L_max) {
+            L_max = L;
+            best_alpha = curr_alpha;
+        }
+    }
+
+    *alpha = best_alpha;
+
+    return PLFIT_SUCCESS;
+}
+
+static int plfit_i_estimate_alpha_discrete_lbfgs(double* xs, size_t n, double xmin,
+        double* alpha, const plfit_discrete_options_t* options, plfit_bool_t sorted) {
+    lbfgs_parameter_t param;
+    lbfgsfloatval_t* variables;
+    plfit_i_estimate_alpha_discrete_data_t data;
+    int ret;
+
+    XMIN_CHECK_ONE;
+
+    /* Initialize algorithm parameters */
+    lbfgs_parameter_init(&param);
+    param.max_iterations = 0;   /* proceed until infinity */
+
+    /* Set up context for optimization */
+    data.xmin = xmin;
+    if (sorted) {
+        data.logsum = plfit_i_logsum_discrete(xs, xs+n, xmin);
+        data.m = n;
+    } else {
+        plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &data.logsum, &data.m);
+    }
+
+    /* Allocate space for the single alpha variable */
+    variables = lbfgs_malloc(1);
+    variables[0] = 3.0;       /* initial guess */
+
+    /* Optimization */
+    ret = lbfgs(1, variables, /* ptr_fx = */ 0,
+            plfit_i_estimate_alpha_discrete_lbfgs_evaluate,
+            plfit_i_estimate_alpha_discrete_lbfgs_progress,
+            &data, &param);
+
+    if (ret < 0 &&
+        ret != LBFGSERR_ROUNDING_ERROR &&
+        ret != LBFGSERR_MAXIMUMLINESEARCH &&
+        ret != LBFGSERR_MINIMUMSTEP &&
+        ret != LBFGSERR_CANCELED) {
+        char buf[4096];
+        snprintf(buf, 4096, "L-BFGS optimization signaled an error (error code = %d)", ret);
+        lbfgs_free(variables);
+        PLFIT_ERROR(buf, PLFIT_FAILURE);
+    }
+    *alpha = variables[0];
+
+    /* Deallocate the variable array */
+    lbfgs_free(variables);
+
+    return PLFIT_SUCCESS;
+}
+
+static int plfit_i_estimate_alpha_discrete_fast(double* xs, size_t n, double xmin,
+        double* alpha, const plfit_discrete_options_t* options, plfit_bool_t sorted) {
+    plfit_continuous_options_t cont_options;
+
+    if (!options)
+        options = &plfit_discrete_default_options;
+
+    plfit_continuous_options_init(&cont_options);
+    cont_options.finite_size_correction = options->finite_size_correction;
+
+    XMIN_CHECK_ONE;
+
+    if (sorted) {
+        return plfit_i_estimate_alpha_continuous_sorted(xs, n, xmin-0.5, alpha);
+    } else {
+        return plfit_i_estimate_alpha_continuous(xs, n, xmin-0.5, alpha);
+    }
+}
+
+static int plfit_i_estimate_alpha_discrete(double* xs, size_t n, double xmin,
+        double* alpha, const plfit_discrete_options_t* options,
+        plfit_bool_t sorted) {
+    switch (options->alpha_method) {
+        case PLFIT_LBFGS:
+            PLFIT_CHECK(plfit_i_estimate_alpha_discrete_lbfgs(xs, n, xmin, alpha,
+                        options, sorted));
+            break;
+
+        case PLFIT_LINEAR_SCAN:
+            PLFIT_CHECK(plfit_i_estimate_alpha_discrete_linear_scan(xs, n, xmin,
+                        alpha, options, sorted));
+            break;
+
+        case PLFIT_PRETEND_CONTINUOUS:
+            PLFIT_CHECK(plfit_i_estimate_alpha_discrete_fast(xs, n, xmin,
+                        alpha, options, sorted));
+            break;
+
+        default:
+            PLFIT_ERROR("unknown optimization method specified", PLFIT_EINVAL);
+    }
+
+    return PLFIT_SUCCESS;
+}
+
+static int plfit_i_ks_test_discrete(double* xs, double* xs_end, const double alpha,
+        const double xmin, double* D) {
+    /* Assumption: xs is sorted and cut off at xmin so the first element is
+     * always larger than or equal to xmin. */
+    double result = 0, n, lnhzeta, x;
+    int m = 0;
+
+    n = xs_end - xs;
+    lnhzeta = hsl_sf_lnhzeta(alpha, xmin);
+
+    while (xs < xs_end) {
+        double d;
+
+        x = *xs;
+
+        /* Re the next line: this used to be the following:
+         *
+         * fabs( 1 - hzeta(alpha, x) / hzeta(alpha, xmin) - m / n)
+         *
+         * However, using the Hurwitz zeta directly sometimes yields
+         * underflows (see Github pull request #17 and related issues).
+         * hzeta(alpha, x) / hzeta(alpha, xmin) can be replaced with
+         * exp(lnhzeta(alpha, x) - lnhzeta(alpha, xmin)), but then
+         * we have 1 - exp(something), which is better to calculate
+         * with a dedicated expm1() function.
+         */
+        d = fabs( expm1( hsl_sf_lnhzeta(alpha, x) - lnhzeta ) + m / n);
+
+        if (d > result)
+            result = d;
+
+        do {
+            xs++; m++;
+        } while (xs < xs_end && *xs == x);
+    }
+
+    *D = result;
+
+    return PLFIT_SUCCESS;
+}
+
+static int plfit_i_calculate_p_value_discrete(double* xs, size_t n,
+        const plfit_discrete_options_t* options, plfit_bool_t xmin_fixed,
+        plfit_result_t *result) {
+    long int num_trials;
+    long int successes = 0;
+    double *xs_head;
+    size_t num_smaller;
+    plfit_discrete_options_t options_no_p_value = *options;
+    int retval = PLFIT_SUCCESS;
+
+    if (options->p_value_method == PLFIT_P_VALUE_SKIP) {
+        /* skipping p-value calculation */
+        result->p = NAN;
+        return PLFIT_SUCCESS;
+    }
+
+    if (options->p_value_method == PLFIT_P_VALUE_APPROXIMATE) {
+        /* p-value approximation; most likely an upper bound */
+        num_smaller = count_smaller(xs, xs + n, result->xmin);
+        result->p = plfit_ks_test_one_sample_p(result->D, n - num_smaller);
+        return PLFIT_SUCCESS;
+    }
+
+    options_no_p_value.p_value_method = PLFIT_P_VALUE_SKIP;
+    num_trials = (long int)(0.25 / options->p_value_precision / options->p_value_precision);
+    if (num_trials <= 0) {
+        PLFIT_ERROR("invalid p-value precision", PLFIT_EINVAL);
+    }
+
+    /* Extract the head of xs that contains elements smaller than xmin */
+    xs_head = extract_smaller(xs, xs+n, result->xmin, &num_smaller);
+    if (xs_head == 0)
+        PLFIT_ERROR("cannot calculate exact p-value", PLFIT_ENOMEM);
+
+#ifdef _OPENMP
+#pragma omp parallel
+#endif
+    {
+        /* Parallel section starts here. If we are compiling using OpenMP, each
+         * thread will use its own RNG that is seeded from the master RNG. If
+         * we are compiling without OpenMP, there is only one thread and it uses
+         * the master RNG. This section must be critical to ensure that only one
+         * thread is using the master RNG at the same time. */
+#ifdef _OPENMP
+        mt_rng_t private_rng;
+#endif
+        mt_rng_t *p_rng;
+        double *ys;
+        long int i;
+        plfit_result_t result_synthetic;
+
+#ifdef _OPENMP
+#pragma omp critical
+        {
+            p_rng = &private_rng;
+            mt_init_from_rng(p_rng, options->rng);
+        }
+#else
+        p_rng = options->rng;
+#endif
+
+        /* Allocate memory to sample into */
+        ys = calloc(n, sizeof(double));
+        if (ys == 0) {
+            retval = PLFIT_ENOMEM;
+        } else {
+            /* The main for loop starts here. */
+#ifdef _OPENMP
+#pragma omp for reduction(+:successes)
+#endif
+            for (i = 0; i < num_trials; i++) {
+                plfit_i_resample_discrete(xs_head, num_smaller, n, result->alpha,
+                        result->xmin, n, p_rng, ys);
+                if (xmin_fixed) {
+                    plfit_estimate_alpha_discrete(ys, n, result->xmin,
+                                &options_no_p_value, &result_synthetic);
+                } else {
+                    plfit_discrete(ys, n, &options_no_p_value, &result_synthetic);
+                }
+                if (result_synthetic.D > result->D)
+                    successes++;
+            }
+
+            free(ys);
+        }
+
+        /* End of parallelized part */
+    }
+
+    free(xs_head);
+
+    if (retval == PLFIT_SUCCESS) {
+        result->p = successes / ((double)num_trials);
+    } else {
+        PLFIT_ERROR("cannot calculate exact p-value", retval);
+    }
+
+    return retval;
+}
+
+int plfit_log_likelihood_discrete(double* xs, size_t n, double alpha, double xmin, double* L) {
+    double result;
+    size_t m;
+
+    if (alpha <= 1) {
+        PLFIT_ERROR("alpha must be greater than one", PLFIT_EINVAL);
+    }
+    XMIN_CHECK_ONE;
+
+    plfit_i_logsum_less_than_discrete(xs, xs+n, xmin, &result, &m);
+    result = - alpha * result - m * hsl_sf_lnhzeta(alpha, xmin);
+
+    *L = result;
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_estimate_alpha_discrete(double* xs, size_t n, double xmin,
+        const plfit_discrete_options_t* options, plfit_result_t *result) {
+    double *xs_copy, *begin, *end;
+
+    if (!options)
+        options = &plfit_discrete_default_options;
+
+    /* Check the validity of the input parameters */
+    DATA_POINTS_CHECK;
+    if (options->alpha_method == PLFIT_LINEAR_SCAN) {
+        if (options->alpha.min <= 1.0) {
+            PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
+        }
+        if (options->alpha.max < options->alpha.min) {
+            PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
+        }
+        if (options->alpha.step <= 0) {
+            PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
+        }
+    }
+
+    PLFIT_CHECK(plfit_i_copy_and_sort(xs, n, &xs_copy));
+
+    begin = xs_copy; end = xs_copy + n;
+    while (begin < end && *begin < xmin)
+        begin++;
+
+    PLFIT_CHECK(plfit_i_estimate_alpha_discrete(begin, end-begin, xmin, &result->alpha,
+                options, /* sorted = */ 1));
+    PLFIT_CHECK(plfit_i_ks_test_discrete(begin, end, result->alpha, xmin, &result->D));
+
+    result->xmin = xmin;
+    if (options->finite_size_correction)
+        plfit_i_perform_finite_size_correction(result, end-begin);
+
+    PLFIT_CHECK(plfit_log_likelihood_discrete(begin, end-begin, result->alpha,
+                result->xmin, &result->L));
+    PLFIT_CHECK(plfit_i_calculate_p_value_discrete(xs, n, options, 1, result));
+
+    free(xs_copy);
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_discrete(double* xs, size_t n, const plfit_discrete_options_t* options,
+        plfit_result_t* result) {
+    double curr_D, curr_alpha;
+    plfit_result_t best_result;
+    double *xs_copy, *px, *end, *end_xmin, prev_x;
+    size_t best_n;
+    int m;
+
+    if (!options)
+        options = &plfit_discrete_default_options;
+
+    /* Check the validity of the input parameters */
+    DATA_POINTS_CHECK;
+    if (options->alpha_method == PLFIT_LINEAR_SCAN) {
+        if (options->alpha.min <= 1.0) {
+            PLFIT_ERROR("alpha.min must be greater than 1.0", PLFIT_EINVAL);
+        }
+        if (options->alpha.max < options->alpha.min) {
+            PLFIT_ERROR("alpha.max must be greater than alpha.min", PLFIT_EINVAL);
+        }
+        if (options->alpha.step <= 0) {
+            PLFIT_ERROR("alpha.step must be positive", PLFIT_EINVAL);
+        }
+    }
+
+    PLFIT_CHECK(plfit_i_copy_and_sort(xs, n, &xs_copy));
+
+    best_result.D = DBL_MAX;
+    best_result.xmin = 1;
+    best_result.alpha = 1;
+    best_n = 0;
+
+    /* Make sure there are at least three distinct values if possible */
+    px = xs_copy; end = px + n; end_xmin = end - 1; m = 0;
+    prev_x = *end_xmin;
+    while (*end_xmin == prev_x && end_xmin > px)
+        end_xmin--;
+    prev_x = *end_xmin;
+    while (*end_xmin == prev_x && end_xmin > px)
+        end_xmin--;
+
+    prev_x = 0;
+    while (px < end_xmin) {
+        while (px < end_xmin && *px == prev_x) {
+            px++; m++;
+        }
+
+        plfit_i_estimate_alpha_discrete(px, n-m, *px, &curr_alpha, options,
+                /* sorted = */ 1);
+        plfit_i_ks_test_discrete(px, end, curr_alpha, *px, &curr_D);
+
+        if (curr_D < best_result.D) {
+            best_result.alpha = curr_alpha;
+            best_result.xmin = *px;
+            best_result.D = curr_D;
+            best_n = n-m;
+        }
+
+        prev_x = *px;
+        px++; m++;
+    }
+
+    *result = best_result;
+    if (options->finite_size_correction)
+        plfit_i_perform_finite_size_correction(result, best_n);
+
+    PLFIT_CHECK(plfit_log_likelihood_discrete(xs_copy+(n-best_n), best_n,
+                result->alpha, result->xmin, &result->L));
+    PLFIT_CHECK(plfit_i_calculate_p_value_discrete(xs_copy, n, options, 0, result));
+
+    free(xs_copy);
+
+    return PLFIT_SUCCESS;
+}
+
+/***** resampling routines to generate synthetic replicates ****/
+
+static int plfit_i_resample_continuous(double* xs_head, size_t num_smaller,
+        size_t n, double alpha, double xmin, size_t num_samples, mt_rng_t* rng,
+        double* result)
+{
+    size_t num_orig_samples, i;
+
+    /* Calculate how many samples have to be drawn from xs_head */
+    num_orig_samples = (size_t) plfit_rbinom(num_samples, num_smaller / (double)n, rng);
+
+    /* Draw the samples from xs_head */
+    for (i = 0; i < num_orig_samples; i++, result++) {
+        *result = xs_head[(size_t)plfit_runif(0, num_smaller, rng)];
+    }
+
+    /* Draw the remaining samples from the fitted distribution */
+    PLFIT_CHECK(plfit_rpareto_array(xmin, alpha-1, num_samples-num_orig_samples, rng,
+            result));
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_resample_continuous(double* xs, size_t n, double alpha, double xmin,
+        size_t num_samples, mt_rng_t* rng, double* result) {
+    double *xs_head;
+    size_t num_smaller = 0;
+    int retval;
+
+    /* Extract the head of xs that contains elements smaller than xmin */
+    xs_head = extract_smaller(xs, xs+n, xmin, &num_smaller);
+    if (xs_head == 0)
+        PLFIT_ERROR("cannot resample continuous dataset", PLFIT_ENOMEM);
+
+    retval = plfit_i_resample_continuous(xs_head, num_smaller, n, alpha, xmin,
+                num_samples, rng, result);
+
+    /* Free xs_head; we don't need it any more */
+    free(xs_head);
+
+    return retval;
+}
+
+static int plfit_i_resample_discrete(double* xs_head, size_t num_smaller, size_t n,
+        double alpha, double xmin, size_t num_samples, mt_rng_t* rng,
+        double* result)
+{
+    size_t num_orig_samples, i;
+
+    /* Calculate how many samples have to be drawn from xs_head */
+    num_orig_samples = (size_t) plfit_rbinom(num_samples, num_smaller / (double)n, rng);
+
+    /* Draw the samples from xs_head */
+    for (i = 0; i < num_orig_samples; i++, result++) {
+        *result = xs_head[(size_t)plfit_runif(0, num_smaller, rng)];
+    }
+
+    /* Draw the remaining samples from the fitted distribution */
+    PLFIT_CHECK(plfit_rzeta_array((long int)xmin, alpha,
+                num_samples-num_orig_samples, rng, result));
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_resample_discrete(double* xs, size_t n, double alpha, double xmin,
+        size_t num_samples, mt_rng_t* rng, double* result) {
+    double *xs_head;
+    size_t num_smaller = 0;
+    int retval;
+
+    /* Extract the head of xs that contains elements smaller than xmin */
+    xs_head = extract_smaller(xs, xs+n, xmin, &num_smaller);
+    if (xs_head == 0)
+        PLFIT_ERROR("cannot resample discrete dataset", PLFIT_ENOMEM);
+
+    retval = plfit_i_resample_discrete(xs_head, num_smaller, n, alpha, xmin,
+                num_samples, rng, result);
+
+    /* Free xs_head; we don't need it any more */
+    free(xs_head);
+
+    return retval;
+}
+
+/******** calculating the p-value of a fitted model only *******/
+
+int plfit_calculate_p_value_continuous(double* xs, size_t n,
+        const plfit_continuous_options_t* options, plfit_bool_t xmin_fixed,
+        plfit_result_t *result) {
+    double* xs_copy;
+
+    PLFIT_CHECK(plfit_i_copy_and_sort(xs, n, &xs_copy));
+    PLFIT_CHECK(plfit_i_calculate_p_value_continuous(xs_copy, n, options,
+                xmin_fixed, result));
+    free(xs_copy);
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_calculate_p_value_discrete(double* xs, size_t n,
+        const plfit_discrete_options_t* options, plfit_bool_t xmin_fixed,
+        plfit_result_t *result) {
+    double* xs_copy;
+
+    PLFIT_CHECK(plfit_i_copy_and_sort(xs, n, &xs_copy));
+    PLFIT_CHECK(plfit_i_calculate_p_value_discrete(xs_copy, n, options,
+                xmin_fixed, result));
+    free(xs_copy);
+
+    return PLFIT_SUCCESS;
+}
diff --git a/igraph/src/pottsmodel_2.cpp b/igraph/src/pottsmodel_2.cpp
--- a/igraph/src/pottsmodel_2.cpp
+++ b/igraph/src/pottsmodel_2.cpp
@@ -42,18 +42,17 @@
  *                                                                         *
  ***************************************************************************/
 
-#include <cstdlib>
-#include <cstdio>
-#include <cstring>
-#include <cmath>
 #include "pottsmodel_2.h"
 #include "NetRoutines.h"
 
-using namespace std;
-
 #include "igraph_random.h"
 #include "igraph_interrupt_internal.h"
 #include "config.h"
+
+#include <cstring>
+#include <cmath>
+
+using namespace std;
 
 //#################################################################################################
 PottsModel::PottsModel(network *n, unsigned int qvalue, int m) : acceptance(0) {
diff --git a/igraph/src/prpack_solver.cpp b/igraph/src/prpack_solver.cpp
--- a/igraph/src/prpack_solver.cpp
+++ b/igraph/src/prpack_solver.cpp
@@ -237,7 +237,7 @@
     } else {
         // TODO: throw exception
     }
-    ret->method = m.c_str();
+    ret->method = m;
     ret->read_time = read_time;
     ret->preprocess_time = preprocess_time;
     ret->compute_time = compute_time;
diff --git a/igraph/src/prpack_utils.cpp b/igraph/src/prpack_utils.cpp
--- a/igraph/src/prpack_utils.cpp
+++ b/igraph/src/prpack_utils.cpp
@@ -16,7 +16,7 @@
 #include "igraph_error.h"
 #endif
 
-#if defined(_WIN32) || defined(_WIN64)
+#if defined(_WIN32)
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
diff --git a/igraph/src/qsort.c b/igraph/src/qsort.c
--- a/igraph/src/qsort.c
+++ b/igraph/src/qsort.c
@@ -31,6 +31,8 @@
  * SUCH DAMAGE.
  */
 
+#include "igraph_qsort.h"
+
 #ifdef _MSC_VER
     /* MSVC does not have inline when compiling C source files */
     #define inline __inline
@@ -76,9 +78,7 @@
                                    es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
 
 static inline void
-swapfunc(a, b, n, swaptype)
-char *a, *b;
-int n, swaptype;
+swapfunc(char *a, char *b, int n, int swaptype)
 {
     if (swaptype <= 1)
         swapcode(long, a, b, n)
diff --git a/igraph/src/random.c b/igraph/src/random.c
--- a/igraph/src/random.c
+++ b/igraph/src/random.c
@@ -22,22 +22,20 @@
 */
 
 #include "igraph_random.h"
+#include "igraph_nongraph.h"
 #include "igraph_error.h"
-#include "config.h"
-
-#include <math.h>
-#include <limits.h>
-#include <string.h>
 #include "igraph_math.h"
 #include "igraph_types.h"
 #include "igraph_vector.h"
 #include "igraph_memory.h"
-#include "igraph_matrix.h"
+#include "config.h"
+#include <math.h>
+#include <string.h>
 
 /**
  * \section about_rngs
  *
- * <section>
+ * <section id="about-random-numbers-in-igraph">
  * <title>About random numbers in igraph, use cases</title>
  *
  * <para>
@@ -54,9 +52,9 @@
 /**
  * \section rng_use_cases
  *
- * <section><title>Use cases</title>
+ * <section id="random-use-cases"><title>Use cases</title>
  *
- * <section><title>Normal (default) use</title>
+ * <section id="random-normal-use"><title>Normal (default) use</title>
  * <para>
  * If the user does not use any of the RNG functions explicitly, but calls
  * some of the randomized igraph functions, then a default RNG is set
@@ -73,7 +71,7 @@
  * </para>
  * </section>
  *
- * <section><title>Reproducible simulations</title>
+ * <section id="random-reproducible-simulations"><title>Reproducible simulations</title>
  * <para>
  * If reproducible results are needed, then the user should set the
  * seed of the default random number generator explicitly, using the
@@ -84,7 +82,7 @@
  * </para>
  * </section>
  *
- * <section><title>Changing the default generator</title>
+ * <section id="random-changing-default-generator"><title>Changing the default generator</title>
  * <para>
  * By default igraph uses the \ref igraph_rng_default() random number
  * generator. This can be changed any time by calling \ref
@@ -94,7 +92,7 @@
  * </para>
  * </section>
  *
- * <section><title>Using multiple generators</title>
+ * <section id="random-using-multiple-generators"><title>Using multiple generators</title>
  * <para>
  * igraph also provides functions to set up multiple random number
  * generators, using the \ref igraph_rng_init() function, and then
@@ -110,7 +108,7 @@
  * </para>
  * </section>
  *
- * <section><title>Example</title>
+ * <section id="random-example"><title>Example</title>
  * <para>
  * \example examples/simple/random_seed.c
  * </para>
@@ -126,8 +124,7 @@
     long int x[31];
 } igraph_i_rng_glibc2_state_t;
 
-unsigned long int igraph_i_rng_glibc2_get(int *i, int *j, int n,
-        long int *x) {
+static unsigned long int igraph_i_rng_glibc2_get(int *i, int *j, int n, long int *x) {
     unsigned long int k;
 
     x[*i] += x[*j];
@@ -158,8 +155,8 @@
 
 /* this function is independent of the bit size */
 
-void igraph_i_rng_glibc2_init(long int *x, int n,
-                              unsigned long int s) {
+static void igraph_i_rng_glibc2_init(long int *x, int n,
+                                     unsigned long int s) {
     int i;
 
     if (s == 0) {
@@ -514,7 +511,7 @@
  *
  * \param rng The random number generator to use as default from now
  *    on. Calling \ref igraph_rng_destroy() on it, while it is still
- *    being used as the default will result craches and/or
+ *    being used as the default will result crashes and/or
  *    unpredictable results.
  *
  * Time complexity: O(1).
@@ -977,8 +974,9 @@
  * result vector.
  */
 
-int igraph_i_random_sample_alga(igraph_vector_t *res, igraph_integer_t l, igraph_integer_t h,
-                                igraph_integer_t length) {
+static int igraph_i_random_sample_alga(igraph_vector_t *res,
+                                       igraph_integer_t l, igraph_integer_t h,
+                                       igraph_integer_t length) {
     igraph_real_t N = h - l + 1;
     igraph_real_t n = length;
 
@@ -1538,7 +1536,7 @@
     return (x < y) ? x : y;
 }
 
-#if HAVE_WORKING_ISFINITE || HAVE_ISFINITE
+#if HAVE_WORKING_ISFINITE || HAVE_DECL_ISFINITE
     /* isfinite is defined in <math.h> according to C99 */
     #define R_FINITE(x)    isfinite(x)
 #elif HAVE_WORKING_FINITE || HAVE_FINITE
@@ -1556,7 +1554,7 @@
 #endif
 
 int R_finite(double x) {
-#if HAVE_WORKING_ISFINITE || HAVE_ISFINITE
+#if HAVE_WORKING_ISFINITE || HAVE_DECL_ISFINITE
     return isfinite(x);
 #elif HAVE_WORKING_FINITE || HAVE_FINITE
     return finite(x);
diff --git a/igraph/src/random_walk.c b/igraph/src/random_walk.c
--- a/igraph/src/random_walk.c
+++ b/igraph/src/random_walk.c
@@ -43,7 +43,7 @@
  * \param start The start vertex for the walk.
  * \param steps The number of steps to take. If the random walk gets
  *   stuck, then the \p stuck argument specifies what happens.
- * \param mode How to walk along the edges in direted graphs.
+ * \param mode How to walk along the edges in directed graphs.
  *   \c IGRAPH_OUT means following edge directions, \c IGRAPH_IN means
  *   going opposite the edge directions, \c IGRAPH_ALL means ignoring
  *   edge directions. This argument is ignored for undirected graphs.
@@ -142,7 +142,7 @@
  * \param start The start vertex for the walk.
  * \param steps The number of steps to take. If the random walk gets
  *   stuck, then the \p stuck argument specifies what happens.
- * \param mode How to walk along the edges in direted graphs.
+ * \param mode How to walk along the edges in directed graphs.
  *   \c IGRAPH_OUT means following edge directions, \c IGRAPH_IN means
  *   going opposite the edge directions, \c IGRAPH_ALL means ignoring
  *   edge directions. This argument is ignored for undirected graphs.
diff --git a/igraph/src/rbinom.c b/igraph/src/rbinom.c
new file mode 100644
--- /dev/null
+++ b/igraph/src/rbinom.c
@@ -0,0 +1,209 @@
+/*
+ *  Mathlib : A C Library of Special Functions
+ *  Copyright (C) 1998 Ross Ihaka
+ *  Copyright (C) 2000-2002 The R Core Team
+ *  Copyright (C) 2007 The R Foundation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  http://www.r-project.org/Licenses/
+ *
+ *  SYNOPSIS
+ *
+ *	#include <Rmath.h>
+ *	double rbinom(double nin, double pp)
+ *
+ *  DESCRIPTION
+ *
+ *	Random variates from the binomial distribution.
+ *
+ *  REFERENCE
+ *
+ *	Kachitvichyanukul, V. and Schmeiser, B. W. (1988).
+ *	Binomial random variate generation.
+ *	Communications of the ACM 31, 216-222.
+ *	(Algorithm BTPEC).
+ */
+
+/*
+ * Modifications for this file were performed by Tamas Nepusz to make it fit
+ * better with plfit. The license of the original file applies to the
+ * modifications as well.
+ */
+
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "sampling.h"
+#include "platform.h"
+
+#define repeat for(;;)
+
+double plfit_rbinom(double nin, double pp, mt_rng_t* rng)
+{
+    /* FIXME: These should become THREAD_specific globals : */
+
+    static double c, fm, npq, p1, p2, p3, p4, qn;
+    static double xl, xll, xlr, xm, xr;
+
+    static double psave = -1.0;
+    static int nsave = -1;
+    static int m;
+
+    double f, f1, f2, u, v, w, w2, x, x1, x2, z, z2;
+    double p, q, np, g, r, al, alv, amaxp, ffm, ynorm;
+    int i, ix, k, n;
+
+    if (!isfinite(nin)) return NAN;
+    r = floor(nin + 0.5);
+    if (r != nin) return NAN;
+    if (!isfinite(pp) ||
+	/* n=0, p=0, p=1 are not errors <TSL>*/
+	r < 0 || pp < 0. || pp > 1.) return NAN;
+
+    if (r == 0 || pp == 0.) return 0;
+    if (pp == 1.) return r;
+
+    n = (int) r;
+
+    p = fmin(pp, 1. - pp);
+    q = 1. - p;
+    np = n * p;
+    r = p / q;
+    g = r * (n + 1);
+
+    /* Setup, perform only when parameters change [using static (globals): */
+
+    /* FIXING: Want this thread safe
+       -- use as little (thread globals) as possible
+    */
+    if (pp != psave || n != nsave) {
+	psave = pp;
+	nsave = n;
+	if (np < 30.0) {
+	    /* inverse cdf logic for mean less than 30 */
+	    qn = pow(q, (double) n);
+	    goto L_np_small;
+	} else {
+	    ffm = np + p;
+	    m = (int) ffm;
+	    fm = m;
+	    npq = np * q;
+	    p1 = (int)(2.195 * sqrt(npq) - 4.6 * q) + 0.5;
+	    xm = fm + 0.5;
+	    xl = xm - p1;
+	    xr = xm + p1;
+	    c = 0.134 + 20.5 / (15.3 + fm);
+	    al = (ffm - xl) / (ffm - xl * p);
+	    xll = al * (1.0 + 0.5 * al);
+	    al = (xr - ffm) / (xr * q);
+	    xlr = al * (1.0 + 0.5 * al);
+	    p2 = p1 * (1.0 + c + c);
+	    p3 = p2 + c / xll;
+	    p4 = p3 + c / xlr;
+	}
+    } else if (n == nsave) {
+	if (np < 30.0)
+	    goto L_np_small;
+    }
+
+    /*-------------------------- np = n*p >= 30 : ------------------- */
+    repeat {
+      u = plfit_runif_01(rng) * p4;
+      v = plfit_runif_01(rng);
+      /* triangular region */
+      if (u <= p1) {
+	  ix = (int)(xm - p1 * v + u);
+	  goto finis;
+      }
+      /* parallelogram region */
+      if (u <= p2) {
+	  x = xl + (u - p1) / c;
+	  v = v * c + 1.0 - fabs(xm - x) / p1;
+	  if (v > 1.0 || v <= 0.)
+	      continue;
+	  ix = (int) x;
+      } else {
+	  if (u > p3) {	/* right tail */
+	      ix = (int)(xr - log(v) / xlr);
+	      if (ix > n)
+		  continue;
+	      v = v * (u - p3) * xlr;
+	  } else {/* left tail */
+	      ix = (int)(xl + log(v) / xll);
+	      if (ix < 0)
+		  continue;
+	      v = v * (u - p2) * xll;
+	  }
+      }
+      /* determine appropriate way to perform accept/reject test */
+      k = abs(ix - m);
+      if (k <= 20 || k >= npq / 2 - 1) {
+	  /* explicit evaluation */
+	  f = 1.0;
+	  if (m < ix) {
+	      for (i = m + 1; i <= ix; i++)
+		  f *= (g / i - r);
+	  } else if (m != ix) {
+	      for (i = ix + 1; i <= m; i++)
+		  f /= (g / i - r);
+	  }
+	  if (v <= f)
+	      goto finis;
+      } else {
+	  /* squeezing using upper and lower bounds on log(f(x)) */
+	  amaxp = (k / npq) * ((k * (k / 3. + 0.625) + 0.1666666666666) / npq + 0.5);
+	  ynorm = -k * k / (2.0 * npq);
+	  alv = log(v);
+	  if (alv < ynorm - amaxp)
+	      goto finis;
+	  if (alv <= ynorm + amaxp) {
+	      /* stirling's formula to machine accuracy */
+	      /* for the final acceptance/rejection test */
+	      x1 = ix + 1;
+	      f1 = fm + 1.0;
+	      z = n + 1 - fm;
+	      w = n - ix + 1.0;
+	      z2 = z * z;
+	      x2 = x1 * x1;
+	      f2 = f1 * f1;
+	      w2 = w * w;
+	      if (alv <= xm * log(f1 / x1) + (n - m + 0.5) * log(z / w) + (ix - m) * log(w * p / (x1 * q)) + (13860.0 - (462.0 - (132.0 - (99.0 - 140.0 / f2) / f2) / f2) / f2) / f1 / 166320.0 + (13860.0 - (462.0 - (132.0 - (99.0 - 140.0 / z2) / z2) / z2) / z2) / z / 166320.0 + (13860.0 - (462.0 - (132.0 - (99.0 - 140.0 / x2) / x2) / x2) / x2) / x1 / 166320.0 + (13860.0 - (462.0 - (132.0 - (99.0 - 140.0 / w2) / w2) / w2) / w2) / w / 166320.)
+		  goto finis;
+	  }
+      }
+  }
+
+ L_np_small:
+    /*---------------------- np = n*p < 30 : ------------------------- */
+
+  repeat {
+     ix = 0;
+     f = qn;
+     u = plfit_runif_01(rng);
+     repeat {
+	 if (u < f)
+	     goto finis;
+	 if (ix > 110)
+	     break;
+	 u -= f;
+	 ix++;
+	 f *= (g / ix - r);
+     }
+  }
+ finis:
+    if (psave > 0.5)
+	 ix = n - ix;
+  return (double)ix;
+}
+
diff --git a/igraph/src/reorder.c b/igraph/src/reorder.c
--- a/igraph/src/reorder.c
+++ b/igraph/src/reorder.c
diff --git a/igraph/src/sampling.c b/igraph/src/sampling.c
new file mode 100644
--- /dev/null
+++ b/igraph/src/sampling.c
@@ -0,0 +1,304 @@
+/* sampling.c
+ *
+ * Copyright (C) 2012 Tamas Nepusz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <math.h>
+
+#include "igraph_random.h"
+
+#include "error.h"
+#include "sampling.h"
+#include "platform.h"
+
+inline double plfit_runif(double lo, double hi, mt_rng_t* rng) {
+    if (rng == 0) {
+        return RNG_UNIF(lo, hi);
+    }
+    return lo + mt_uniform_01(rng) * (hi-lo);
+}
+
+inline double plfit_runif_01(mt_rng_t* rng) {
+    if (rng == 0) {
+        return RNG_UNIF01();
+    }
+    return mt_uniform_01(rng);
+}
+
+inline double plfit_rpareto(double xmin, double alpha, mt_rng_t* rng) {
+    if (alpha <= 0 || xmin <= 0)
+        return NAN;
+
+    /* 1-u is used in the base here because we want to avoid the case of
+     * sampling zero */
+    return pow(1-plfit_runif_01(rng), -1.0 / alpha) * xmin;
+}
+
+int plfit_rpareto_array(double xmin, double alpha, size_t n, mt_rng_t* rng,
+        double* result) {
+    double gamma;
+
+    if (alpha <= 0 || xmin <= 0)
+        return PLFIT_EINVAL;
+
+    if (result == 0 || n == 0)
+        return PLFIT_SUCCESS;
+
+    gamma = -1.0 / alpha;
+    while (n > 0) {
+        /* 1-u is used in the base here because we want to avoid the case of
+         * sampling zero */
+        *result = pow(1-plfit_runif_01(rng), gamma) * xmin;
+        result++; n--;
+    }
+
+    return PLFIT_SUCCESS;
+}
+
+inline double plfit_rzeta(long int xmin, double alpha, mt_rng_t* rng) {
+    double u, v, t;
+    long int x;
+    double alpha_minus_1 = alpha-1;
+    double minus_1_over_alpha_minus_1 = -1.0 / (alpha-1);
+    double b;
+    double one_over_b_minus_1;
+
+    if (alpha <= 0 || xmin < 1)
+        return NAN;
+
+    xmin = (long int) round(xmin);
+
+    /* Rejection sampling for the win. We use Y=floor(U^{-1/alpha} * xmin) as the
+     * envelope distribution, similarly to Chapter X.6 of Luc Devroye's book
+     * (where xmin is assumed to be 1): http://luc.devroye.org/chapter_ten.pdf
+     *
+     * Some notes that should help me recover what I was doing:
+     *
+     * p_i = 1/zeta(alpha, xmin) * i^-alpha
+     * q_i = (xmin/i)^{alpha-1} - (xmin/(i+1))^{alpha-1}
+     *     = (i/xmin)^{1-alpha} - ((i+1)/xmin)^{1-alpha}
+     *     = [i^{1-alpha} - (i+1)^{1-alpha}] / xmin^{1-alpha}
+     *
+     * p_i / q_i attains its maximum at xmin=i, so the rejection constant is:
+     *
+     * c = p_xmin / q_xmin
+     *
+     * We have to accept the sample if V <= (p_i / q_i) * (q_xmin / p_xmin) =
+     * (i/xmin)^-alpha * [xmin^{1-alpha} - (xmin+1)^{1-alpha}] / [i^{1-alpha} - (i+1)^{1-alpha}] =
+     * [xmin - xmin^alpha / (xmin+1)^{alpha-1}] / [i - i^alpha / (i+1)^{alpha-1}] =
+     * xmin/i * [1-(xmin/(xmin+1))^{alpha-1}]/[1-(i/(i+1))^{alpha-1}]
+     *
+     * In other words (and substituting i with X, which is the same),
+     *
+     * V * (X/xmin) <= [1 - (1+1/xmin)^{1-alpha}] / [1 - (1+1/i)^{1-alpha}]
+     *
+     * Let b := (1+1/xmin)^{alpha-1} and let T := (1+1/i)^{alpha-1}. Then:
+     *
+     * V * (X/xmin) <= [(b-1)/b] / [(T-1)/T]
+     * V * (X/xmin) * (T-1) / (b-1) <= T / b
+     *
+     * which is the same as in Devroye's book, except for the X/xmin term, and
+     * the definition of b.
+     */
+    b = pow(1 + 1.0/xmin, alpha_minus_1);
+    one_over_b_minus_1 = 1.0/(b-1);
+    do {
+        do {
+            u = plfit_runif_01(rng);
+            v = plfit_runif_01(rng);
+            /* 1-u is used in the base here because we want to avoid the case of
+             * having zero in x */
+            x = (long int) floor(pow(1-u, minus_1_over_alpha_minus_1) * xmin);
+        } while (x < xmin);
+        t = pow((x+1.0)/x, alpha_minus_1);
+    } while (v*x*(t-1)*one_over_b_minus_1*b > t*xmin);
+
+    return x;
+}
+
+int plfit_rzeta_array(long int xmin, double alpha, size_t n, mt_rng_t* rng,
+        double* result) {
+    double u, v, t;
+    long int x;
+    double alpha_minus_1 = alpha-1;
+    double minus_1_over_alpha_minus_1 = -1.0 / (alpha-1);
+    double b, one_over_b_minus_1;
+
+    if (alpha <= 0 || xmin < 1)
+        return PLFIT_EINVAL;
+
+    if (result == 0 || n == 0)
+        return PLFIT_SUCCESS;
+
+    /* See the comments in plfit_rzeta for an explanation of the algorithm
+     * below. */
+    xmin = (long int) round(xmin);
+    b = pow(1 + 1.0/xmin, alpha_minus_1);
+    one_over_b_minus_1 = 1.0/(b-1);
+
+    while (n > 0) {
+        do {
+            do {
+                u = plfit_runif_01(rng);
+                v = plfit_runif_01(rng);
+                /* 1-u is used in the base here because we want to avoid the case of
+                 * having zero in x */
+                x = (long int) floor(pow(1-u, minus_1_over_alpha_minus_1) * xmin);
+            } while (x < xmin);     /* handles overflow as well */
+            t = pow((x+1.0)/x, alpha_minus_1);
+        } while (v*x*(t-1)*one_over_b_minus_1*b > t*xmin);
+        *result = x;
+        if (x < 0) return PLFIT_EINVAL;
+        result++; n--;
+    }
+
+    return PLFIT_SUCCESS;
+}
+
+int plfit_walker_alias_sampler_init(plfit_walker_alias_sampler_t* sampler,
+        double* ps, size_t n) {
+    double *p, *p2, *ps_end;
+    double sum;
+    long int *short_sticks, *long_sticks;
+    long int num_short_sticks, num_long_sticks;
+    size_t i;
+
+    sampler->num_bins = n;
+
+    ps_end = ps + n;
+
+    /* Initialize indexes and probs */
+    sampler->indexes = (long int*)calloc(n, sizeof(long int));
+    if (sampler->indexes == 0) {
+        return PLFIT_ENOMEM;
+    }
+    sampler->probs   = (double*)calloc(n, sizeof(double));
+    if (sampler->probs == 0) {
+        free(sampler->indexes);
+        return PLFIT_ENOMEM;
+    }
+
+    /* Normalize the probability vector; count how many short and long sticks
+     * are there initially */
+    for (sum = 0.0, p = ps; p != ps_end; p++) {
+        sum += *p;
+    }
+    sum = n / sum;
+
+    num_short_sticks = num_long_sticks = 0;
+    for (p = ps, p2 = sampler->probs; p != ps_end; p++, p2++) {
+        *p2 = *p * sum;
+        if (*p2 < 1) {
+            num_short_sticks++;
+        } else if (*p2 > 1) {
+            num_long_sticks++;
+        }
+    }
+
+    /* Allocate space for short & long stick indexes */
+    long_sticks = (long int*)calloc(num_long_sticks, sizeof(long int));
+    if (long_sticks == 0) {
+        free(sampler->probs);
+        free(sampler->indexes);
+        return PLFIT_ENOMEM;
+    }
+    short_sticks = (long int*)calloc(num_long_sticks, sizeof(long int));
+    if (short_sticks == 0) {
+        free(sampler->probs);
+        free(sampler->indexes);
+        free(long_sticks);
+        return PLFIT_ENOMEM;
+    }
+
+    /* Initialize short_sticks and long_sticks */
+    num_short_sticks = num_long_sticks = 0;
+    for (i = 0, p = sampler->probs; i < n; i++, p++) {
+        if (*p < 1) {
+            short_sticks[num_short_sticks++] = i;
+        } else if (*p > 1) {
+            long_sticks[num_long_sticks++] = i;
+        }
+    }
+
+    /* Prepare the index table */
+    while (num_short_sticks && num_long_sticks) {
+        long int short_index, long_index;
+        short_index = short_sticks[--num_short_sticks];
+        long_index = long_sticks[num_long_sticks-1];
+        sampler->indexes[short_index] = long_index;
+        sampler->probs[long_index] =     /* numerical stability */
+            (sampler->probs[long_index] + sampler->probs[short_index]) - 1;
+        if (sampler->probs[long_index] < 1) {
+            short_sticks[num_short_sticks++] = long_index;
+            num_long_sticks--;
+        }
+    }
+
+    /* Fix numerical stability issues */
+    while (num_long_sticks) {
+        i = long_sticks[--num_long_sticks];
+        sampler->probs[i] = 1;
+    }
+    while (num_short_sticks) {
+        i = short_sticks[--num_short_sticks];
+        sampler->probs[i] = 1;
+    }
+
+    return PLFIT_SUCCESS;
+}
+
+
+void plfit_walker_alias_sampler_destroy(plfit_walker_alias_sampler_t* sampler) {
+    if (sampler->indexes) {
+        free(sampler->indexes);
+        sampler->indexes = 0;
+    }
+    if (sampler->probs) {
+        free(sampler->probs);
+        sampler->probs = 0;
+    }
+}
+
+
+int plfit_walker_alias_sampler_sample(const plfit_walker_alias_sampler_t* sampler,
+        long int *xs, size_t n, mt_rng_t* rng) {
+    double u;
+    long int j;
+    long int *x;
+
+    x = xs;
+
+    if (rng == 0) {
+        /* Using built-in RNG */
+        while (n > 0) {
+            u = RNG_UNIF01();
+            j = RNG_INTEGER(0, sampler->num_bins - 1);
+            *x = (u < sampler->probs[j]) ? j : sampler->indexes[j];
+            n--; x++;
+        }
+    } else {
+        /* Using Mersenne Twister */
+        while (n > 0) {
+            u = mt_uniform_01(rng);
+            j = mt_random(rng) % sampler->num_bins;
+            *x = (u < sampler->probs[j]) ? j : sampler->indexes[j];
+            n--; x++;
+        }
+    }
+
+    return PLFIT_SUCCESS;
+}
diff --git a/igraph/src/sbm.c b/igraph/src/sbm.c
--- a/igraph/src/sbm.c
+++ b/igraph/src/sbm.c
@@ -89,7 +89,7 @@
 
     igraph_matrix_minmax(pref_matrix, &minp, &maxp);
     if (minp < 0 || maxp > 1) {
-        IGRAPH_ERROR("Connection probabilities must in [0,1]", IGRAPH_EINVAL);
+        IGRAPH_ERROR("Connection probabilities must be in [0,1]", IGRAPH_EINVAL);
     }
 
     if (n < 0) {
@@ -106,7 +106,7 @@
     }
 
     if (igraph_vector_int_min(block_sizes) < 0) {
-        IGRAPH_ERROR("Block size must be non-negative", IGRAPH_EINVAL);
+        IGRAPH_ERROR("Block sizes must be non-negative", IGRAPH_EINVAL);
     }
 
     if (igraph_vector_int_sum(block_sizes) != n) {
diff --git a/igraph/src/scan.c b/igraph/src/scan.c
--- a/igraph/src/scan.c
+++ b/igraph/src/scan.c
@@ -75,7 +75,7 @@
 }
 
 /* From triangles.c */
-
+/* TODO add to private header */
 int igraph_i_trans4_al_simplify(igraph_adjlist_t *al,
                                 const igraph_vector_int_t *rank);
 
@@ -83,8 +83,8 @@
    "backwards" according to the rank vector. It works on
    edge lists */
 
-int igraph_i_trans4_il_simplify(const igraph_t *graph, igraph_inclist_t *il,
-                                const igraph_vector_int_t *rank) {
+static int igraph_i_trans4_il_simplify(const igraph_t *graph, igraph_inclist_t *il,
+                                       const igraph_vector_int_t *rank) {
 
     long int i;
     long int n = il->length;
@@ -119,10 +119,10 @@
 
 /* This one handles both weighted and unweighted cases */
 
-int igraph_i_local_scan_1_directed(const igraph_t *graph,
-                                   igraph_vector_t *res,
-                                   const igraph_vector_t *weights,
-                                   igraph_neimode_t mode) {
+static int igraph_i_local_scan_1_directed(const igraph_t *graph,
+                                          igraph_vector_t *res,
+                                          const igraph_vector_t *weights,
+                                          igraph_neimode_t mode) {
 
     int no_of_nodes = igraph_vcount(graph);
     igraph_inclist_t incs;
@@ -180,9 +180,9 @@
     return 0;
 }
 
-int igraph_i_local_scan_1_directed_all(const igraph_t *graph,
-                                       igraph_vector_t *res,
-                                       const igraph_vector_t *weights) {
+static int igraph_i_local_scan_1_directed_all(const igraph_t *graph,
+                                              igraph_vector_t *res,
+                                              const igraph_vector_t *weights) {
 
     int no_of_nodes = igraph_vcount(graph);
     igraph_inclist_t incs;
@@ -250,9 +250,9 @@
     return 0;
 }
 
-int igraph_i_local_scan_1_sumweights(const igraph_t *graph,
-                                     igraph_vector_t *res,
-                                     const igraph_vector_t *weights) {
+static int igraph_i_local_scan_1_sumweights(const igraph_t *graph,
+                                            igraph_vector_t *res,
+                                            const igraph_vector_t *weights) {
 
     long int no_of_nodes = igraph_vcount(graph);
     long int node, i, j, nn;
@@ -384,10 +384,10 @@
     return 0;
 }
 
-int igraph_i_local_scan_0_them_w(const igraph_t *us, const igraph_t *them,
-                                 igraph_vector_t *res,
-                                 const igraph_vector_t *weights_them,
-                                 igraph_neimode_t mode) {
+static int igraph_i_local_scan_0_them_w(const igraph_t *us, const igraph_t *them,
+                                        igraph_vector_t *res,
+                                        const igraph_vector_t *weights_them,
+                                        igraph_neimode_t mode) {
 
     igraph_t is;
     igraph_vector_t map2;
diff --git a/igraph/src/scg.c b/igraph/src/scg.c
--- a/igraph/src/scg.c
+++ b/igraph/src/scg.c
@@ -79,6 +79,7 @@
 #include "igraph_eigen.h"
 #include "igraph_interface.h"
 #include "igraph_structural.h"
+#include "igraph_community.h"
 #include "igraph_constructors.h"
 #include "igraph_conversion.h"
 #include "igraph_memory.h"
@@ -121,7 +122,7 @@
  * role, as for instance is the case of dynamical processes on networks.
  * </para>
  *
- * <section><title>SCG in brief</title>
+ * <section id="scg-in-brief"><title>SCG in brief</title>
  * <para>
  * The main idea of SCG is to operate on a matrix a shrinkage operation
  * specifically designed to preserve some of the matrix eigenpairs while
@@ -209,7 +210,7 @@
  * </para>
  * </section>
  *
- * <section><title>Functions for performing SCG</title>
+ * <section id="functions-for-performing-scg"><title>Functions for performing SCG</title>
  * <para>
  * The main functions are \ref igraph_scg_adjacency(), \ref
  * igraph_scg_laplacian() and \ref igraph_scg_stochastic().
@@ -240,7 +241,7 @@
  * </para>
  * </section>
  *
- * <section><title>References</title>
+ * <section id="scg-references"><title>References</title>
  * <para>
  * [1] D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
  * Shrinking Matrices while Preserving their Eigenpairs with Application
@@ -468,16 +469,18 @@
     igraph_matrix_int_destroy(&gr_mat);
     IGRAPH_FINALLY_CLEAN(1);
 
+    IGRAPH_CHECK(igraph_reindex_membership(groups, 0, 0));
+
     return 0;
 }
 
-int igraph_i_scg_semiprojectors_sym(const igraph_vector_t *groups,
-                                    igraph_matrix_t *L,
-                                    igraph_matrix_t *R,
-                                    igraph_sparsemat_t *Lsparse,
-                                    igraph_sparsemat_t *Rsparse,
-                                    int no_of_groups,
-                                    int no_of_nodes) {
+static int igraph_i_scg_semiprojectors_sym(const igraph_vector_t *groups,
+                                           igraph_matrix_t *L,
+                                           igraph_matrix_t *R,
+                                           igraph_sparsemat_t *Lsparse,
+                                           igraph_sparsemat_t *Rsparse,
+                                           int no_of_groups,
+                                           int no_of_nodes) {
 
     igraph_vector_t tab;
     int i;
@@ -536,14 +539,14 @@
     return 0;
 }
 
-int igraph_i_scg_semiprojectors_lap(const igraph_vector_t *groups,
-                                    igraph_matrix_t *L,
-                                    igraph_matrix_t *R,
-                                    igraph_sparsemat_t *Lsparse,
-                                    igraph_sparsemat_t *Rsparse,
-                                    int no_of_groups,
-                                    int no_of_nodes,
-                                    igraph_scg_norm_t norm) {
+static int igraph_i_scg_semiprojectors_lap(const igraph_vector_t *groups,
+                                           igraph_matrix_t *L,
+                                           igraph_matrix_t *R,
+                                           igraph_sparsemat_t *Lsparse,
+                                           igraph_sparsemat_t *Rsparse,
+                                           int no_of_groups,
+                                           int no_of_nodes,
+                                           igraph_scg_norm_t norm) {
 
     igraph_vector_t tab;
     int i;
@@ -633,15 +636,15 @@
     return 0;
 }
 
-int igraph_i_scg_semiprojectors_sto(const igraph_vector_t *groups,
-                                    igraph_matrix_t *L,
-                                    igraph_matrix_t *R,
-                                    igraph_sparsemat_t *Lsparse,
-                                    igraph_sparsemat_t *Rsparse,
-                                    int no_of_groups,
-                                    int no_of_nodes,
-                                    const igraph_vector_t *p,
-                                    igraph_scg_norm_t norm) {
+static int igraph_i_scg_semiprojectors_sto(const igraph_vector_t *groups,
+                                           igraph_matrix_t *L,
+                                           igraph_matrix_t *R,
+                                           igraph_sparsemat_t *Lsparse,
+                                           igraph_sparsemat_t *Rsparse,
+                                           int no_of_groups,
+                                           int no_of_nodes,
+                                           const igraph_vector_t *p,
+                                           igraph_scg_norm_t norm) {
 
     igraph_vector_t pgr, pnormed;
     int i;
@@ -974,9 +977,9 @@
     return 0;
 }
 
-int igraph_i_matrix_laplacian(const igraph_matrix_t *matrix,
-                              igraph_matrix_t *mymatrix,
-                              igraph_scg_norm_t norm) {
+static int igraph_i_matrix_laplacian(const igraph_matrix_t *matrix,
+                                     igraph_matrix_t *mymatrix,
+                                     igraph_scg_norm_t norm) {
 
     igraph_vector_t degree;
     int i, j, n = (int) igraph_matrix_nrow(matrix);
@@ -1006,9 +1009,9 @@
     return 0;
 }
 
-int igraph_i_sparsemat_laplacian(const igraph_sparsemat_t *sparse,
-                                 igraph_sparsemat_t *mysparse,
-                                 igraph_scg_norm_t norm) {
+static int igraph_i_sparsemat_laplacian(const igraph_sparsemat_t *sparse,
+                                        igraph_sparsemat_t *mysparse,
+                                        igraph_scg_norm_t norm) {
 
     igraph_vector_t degree;
     int i, n = (int) igraph_sparsemat_nrow(sparse);
@@ -1058,9 +1061,9 @@
     return 0;
 }
 
-int igraph_i_matrix_stochastic(const igraph_matrix_t *matrix,
-                               igraph_matrix_t *mymatrix,
-                               igraph_scg_norm_t norm) {
+static int igraph_i_matrix_stochastic(const igraph_matrix_t *matrix,
+                                      igraph_matrix_t *mymatrix,
+                                      igraph_scg_norm_t norm) {
 
     int i, j, n = (int) igraph_matrix_nrow(matrix);
     IGRAPH_CHECK(igraph_matrix_copy(mymatrix, matrix));
@@ -1096,12 +1099,13 @@
     return 0;
 }
 
+/* TODO prototype; function is defined in conversion.c */
 int igraph_i_normalize_sparsemat(igraph_sparsemat_t *sparsemat,
                                  igraph_bool_t column_wise);
 
-int igraph_i_sparsemat_stochastic(const igraph_sparsemat_t *sparse,
-                                  igraph_sparsemat_t *mysparse,
-                                  igraph_scg_norm_t norm) {
+static int igraph_i_sparsemat_stochastic(const igraph_sparsemat_t *sparse,
+                                         igraph_sparsemat_t *mysparse,
+                                         igraph_scg_norm_t norm) {
 
     IGRAPH_CHECK(igraph_sparsemat_copy(mysparse, sparse));
     IGRAPH_FINALLY(igraph_sparsemat_destroy, mysparse);
@@ -1112,15 +1116,15 @@
     return 0;
 }
 
-int igraph_i_scg_get_result(igraph_scg_matrix_t type,
-                            const igraph_matrix_t *matrix,
-                            const igraph_sparsemat_t *sparsemat,
-                            const igraph_sparsemat_t *Lsparse,
-                            const igraph_sparsemat_t *Rsparse_t,
-                            igraph_t *scg_graph,
-                            igraph_matrix_t *scg_matrix,
-                            igraph_sparsemat_t *scg_sparsemat,
-                            igraph_bool_t directed) {
+static int igraph_i_scg_get_result(igraph_scg_matrix_t type,
+                                   const igraph_matrix_t *matrix,
+                                   const igraph_sparsemat_t *sparsemat,
+                                   const igraph_sparsemat_t *Lsparse,
+                                   const igraph_sparsemat_t *Rsparse_t,
+                                   igraph_t *scg_graph,
+                                   igraph_matrix_t *scg_matrix,
+                                   igraph_sparsemat_t *scg_sparsemat,
+                                   igraph_bool_t directed) {
 
     /* We need to calculate either scg_matrix (if input is dense), or
        scg_sparsemat (if input is sparse). For the latter we might need
@@ -1269,20 +1273,20 @@
     return 0;
 }
 
-int igraph_i_scg_common_checks(const igraph_t *graph,
-                               const igraph_matrix_t *matrix,
-                               const igraph_sparsemat_t *sparsemat,
-                               const igraph_vector_t *ev,
-                               igraph_integer_t nt,
-                               const igraph_vector_t *nt_vec,
-                               const igraph_matrix_t *vectors,
-                               const igraph_matrix_complex_t *vectors_cmplx,
-                               const igraph_vector_t *groups,
-                               const igraph_t *scg_graph,
-                               const igraph_matrix_t *scg_matrix,
-                               const igraph_sparsemat_t *scg_sparsemat,
-                               const igraph_vector_t *p,
-                               igraph_real_t *evmin, igraph_real_t *evmax) {
+static int igraph_i_scg_common_checks(const igraph_t *graph,
+                                      const igraph_matrix_t *matrix,
+                                      const igraph_sparsemat_t *sparsemat,
+                                      const igraph_vector_t *ev,
+                                      igraph_integer_t nt,
+                                      const igraph_vector_t *nt_vec,
+                                      const igraph_matrix_t *vectors,
+                                      const igraph_matrix_complex_t *vectors_cmplx,
+                                      const igraph_vector_t *groups,
+                                      const igraph_t *scg_graph,
+                                      const igraph_matrix_t *scg_matrix,
+                                      const igraph_sparsemat_t *scg_sparsemat,
+                                      const igraph_vector_t *p,
+                                      igraph_real_t *evmin, igraph_real_t *evmax) {
 
     int no_of_nodes = -1;
     igraph_real_t min, max;
diff --git a/igraph/src/scg_approximate_methods.c b/igraph/src/scg_approximate_methods.c
--- a/igraph/src/scg_approximate_methods.c
+++ b/igraph/src/scg_approximate_methods.c
@@ -64,10 +64,9 @@
  *    centers as used in intervals_plus_kmeans.
  */
 
+#include "scg_headers.h"
 #include "igraph_error.h"
 #include "igraph_types.h"
-#include "scg_headers.h"
-#include "igraph_memory.h"
 #include "igraph_vector.h"
 
 int igraph_i_intervals_plus_kmeans(const igraph_vector_t *v, int *gr,
diff --git a/igraph/src/scg_exact_scg.c b/igraph/src/scg_exact_scg.c
--- a/igraph/src/scg_exact_scg.c
+++ b/igraph/src/scg_exact_scg.c
@@ -29,8 +29,8 @@
  *    See also Section 5.4.1 (last paragraph) of the above reference.
  */
 
-#include "igraph_memory.h"
 #include "scg_headers.h"
+#include "igraph_memory.h"
 #include <math.h>
 
 int igraph_i_exact_coarse_graining(const igraph_real_t *v,
diff --git a/igraph/src/scg_kmeans.c b/igraph/src/scg_kmeans.c
--- a/igraph/src/scg_kmeans.c
+++ b/igraph/src/scg_kmeans.c
@@ -31,8 +31,6 @@
  *    See also Section 5.3.3 of the above reference.
  */
 
-#include "igraph_memory.h"
-
 #include "scg_headers.h"
 
 int igraph_i_kmeans_Lloyd(const igraph_vector_t *x, int n, int p,
diff --git a/igraph/src/scg_optimal_method.c b/igraph/src/scg_optimal_method.c
--- a/igraph/src/scg_optimal_method.c
+++ b/igraph/src/scg_optimal_method.c
@@ -35,13 +35,12 @@
  *    starting from 0.
  */
 
+#include "scg_headers.h"
 #include "igraph_error.h"
 #include "igraph_memory.h"
 #include "igraph_matrix.h"
 #include "igraph_vector.h"
 
-#include "scg_headers.h"
-
 int igraph_i_optimal_partition(const igraph_real_t *v, int *gr, int n,
                                int nt, int matrix, const igraph_real_t *p,
                                igraph_real_t *value) {
@@ -114,7 +113,7 @@
 
     IGRAPH_MATRIX_INIT_FINALLY(&F, nt, n);
     IGRAPH_CHECK(igraph_matrix_int_init(&Q, nt, n));
-    IGRAPH_FINALLY(igraph_matrix_destroy, &Q);
+    IGRAPH_FINALLY(igraph_matrix_int_destroy, &Q);
 
     for (i = 0; i < n; i++) {
         MATRIX(Q, 0, i)++;
@@ -238,4 +237,3 @@
 
     return 0;
 }
-
diff --git a/igraph/src/scg_utils.c b/igraph/src/scg_utils.c
--- a/igraph/src/scg_utils.c
+++ b/igraph/src/scg_utils.c
@@ -27,10 +27,9 @@
  *    functions used throughout the SCGlib.
  */
 
+#include "scg_headers.h"
 #include "igraph_error.h"
 #include "igraph_memory.h"
-
-#include "scg_headers.h"
 
 /*to be used with qsort and struct ind_val arrays */
 int igraph_i_compare_ind_val(const void *a, const void *b) {
diff --git a/igraph/src/separators.c b/igraph/src/separators.c
--- a/igraph/src/separators.c
+++ b/igraph/src/separators.c
@@ -28,21 +28,18 @@
 #include "igraph_vector.h"
 #include "igraph_interface.h"
 #include "igraph_flow.h"
-#include "igraph_flow_internal.h"
 #include "igraph_components.h"
 #include "igraph_structural.h"
-#include "igraph_constructors.h"
-#include "igraph_stack.h"
 #include "igraph_interrupt_internal.h"
 
-int igraph_i_is_separator(const igraph_t *graph,
-                          igraph_vit_t *vit,
-                          long int except,
-                          igraph_bool_t *res,
-                          igraph_vector_bool_t *removed,
-                          igraph_dqueue_t *Q,
-                          igraph_vector_t *neis,
-                          long int no_of_nodes) {
+static int igraph_i_is_separator(const igraph_t *graph,
+                                 igraph_vit_t *vit,
+                                 long int except,
+                                 igraph_bool_t *res,
+                                 igraph_vector_bool_t *removed,
+                                 igraph_dqueue_t *Q,
+                                 igraph_vector_t *neis,
+                                 long int no_of_nodes) {
 
     long int start = 0;
 
@@ -266,11 +263,11 @@
         }                                                  \
     } while (0)
 
-int igraph_i_clusters_leaveout(const igraph_adjlist_t *adjlist,
-                               igraph_vector_t *components,
-                               igraph_vector_t *leaveout,
-                               unsigned long int *mark,
-                               igraph_dqueue_t *Q) {
+static int igraph_i_clusters_leaveout(const igraph_adjlist_t *adjlist,
+                                      igraph_vector_t *components,
+                                      igraph_vector_t *leaveout,
+                                      unsigned long int *mark,
+                                      igraph_dqueue_t *Q) {
 
     /* Another trick: we use the same 'leaveout' vector to mark the
      * vertices that were already found in the BFS
@@ -314,8 +311,8 @@
     return 0;
 }
 
-igraph_bool_t igraph_i_separators_newsep(const igraph_vector_ptr_t *comps,
-        const igraph_vector_t *newc) {
+static igraph_bool_t igraph_i_separators_newsep(const igraph_vector_ptr_t *comps,
+                                                const igraph_vector_t *newc) {
 
     long int co, nocomps = igraph_vector_ptr_size(comps);
 
@@ -330,12 +327,12 @@
     return 1;
 }
 
-int igraph_i_separators_store(igraph_vector_ptr_t *separators,
-                              const igraph_adjlist_t *adjlist,
-                              igraph_vector_t *components,
-                              igraph_vector_t *leaveout,
-                              unsigned long int *mark,
-                              igraph_vector_t *sorter) {
+static int igraph_i_separators_store(igraph_vector_ptr_t *separators,
+                                     const igraph_adjlist_t *adjlist,
+                                     igraph_vector_t *components,
+                                     igraph_vector_t *leaveout,
+                                     unsigned long int *mark,
+                                     igraph_vector_t *sorter) {
 
     /* We need to stote N(C), the neighborhood of C, but only if it is
      * not already stored among the separators.
@@ -387,7 +384,7 @@
     return 0;
 }
 
-void igraph_i_separators_free(igraph_vector_ptr_t *separators) {
+static void igraph_i_separators_free(igraph_vector_ptr_t *separators) {
     long int i, n = igraph_vector_ptr_size(separators);
     for (i = 0; i < n; i++) {
         igraph_vector_t *vec = VECTOR(*separators)[i];
@@ -557,8 +554,8 @@
 
 #undef UPDATEMARK
 
-int igraph_i_minimum_size_separators_append(igraph_vector_ptr_t *old,
-        igraph_vector_ptr_t *new) {
+static int igraph_i_minimum_size_separators_append(igraph_vector_ptr_t *old,
+                                                   igraph_vector_ptr_t *new) {
 
     long int olen = igraph_vector_ptr_size(old);
     long int nlen = igraph_vector_ptr_size(new);
@@ -587,9 +584,9 @@
     return 0;
 }
 
-int igraph_i_minimum_size_separators_topkdeg(const igraph_t *graph,
-        igraph_vector_t *res,
-        long int k) {
+static int igraph_i_minimum_size_separators_topkdeg(const igraph_t *graph,
+                                                    igraph_vector_t *res,
+                                                    long int k) {
     long int no_of_nodes = igraph_vcount(graph);
     igraph_vector_t deg, order;
     long int i;
@@ -612,7 +609,7 @@
     return 0;
 }
 
-void igraph_i_separators_stcuts_free(igraph_vector_ptr_t *p) {
+static void igraph_i_separators_stcuts_free(igraph_vector_ptr_t *p) {
     long int i, n = igraph_vector_ptr_size(p);
     for (i = 0; i < n; i++) {
         igraph_vector_t *v = VECTOR(*p)[i];
diff --git a/igraph/src/sir.c b/igraph/src/sir.c
--- a/igraph/src/sir.c
+++ b/igraph/src/sir.c
@@ -28,15 +28,16 @@
 #include "igraph_psumtree.h"
 #include "igraph_memory.h"
 #include "igraph_structural.h"
+#include "igraph_interrupt_internal.h"
 
 int igraph_sir_init(igraph_sir_t *sir) {
-    igraph_vector_init(&sir->times, 1);
+    IGRAPH_CHECK(igraph_vector_init(&sir->times, 1));
     IGRAPH_FINALLY(igraph_vector_destroy, &sir->times);
-    igraph_vector_int_init(&sir->no_s, 1);
+    IGRAPH_CHECK(igraph_vector_int_init(&sir->no_s, 1));
     IGRAPH_FINALLY(igraph_vector_int_destroy, &sir->no_s);
-    igraph_vector_int_init(&sir->no_i, 1);
+    IGRAPH_CHECK(igraph_vector_int_init(&sir->no_i, 1));
     IGRAPH_FINALLY(igraph_vector_int_destroy, &sir->no_i);
-    igraph_vector_int_init(&sir->no_r, 1);
+    IGRAPH_CHECK(igraph_vector_int_init(&sir->no_r, 1));
     IGRAPH_FINALLY_CLEAN(3);
     return 0;
 }
@@ -55,12 +56,12 @@
     igraph_vector_int_destroy(&sir->no_r);
 }
 
-void igraph_i_sir_destroy(igraph_vector_ptr_t *v) {
+static void igraph_i_sir_destroy(igraph_vector_ptr_t *v) {
     int i, n = igraph_vector_ptr_size(v);
     for (i = 0; i < n; i++) {
-        igraph_sir_t *s = VECTOR(*v)[i];
-        if (s) {
-            igraph_sir_destroy(s);
+        if ( VECTOR(*v)[i] ) {
+            igraph_sir_destroy( VECTOR(*v)[i]) ;
+            igraph_Free( VECTOR(*v)[i] ); /* this also sets the vector_ptr element to NULL */
         }
     }
 }
@@ -127,16 +128,17 @@
         IGRAPH_WARNING("Edge directions are ignored in SIR model");
     }
     if (beta < 0) {
-        IGRAPH_ERROR("Beta must be non-negative in SIR model", IGRAPH_EINVAL);
+        IGRAPH_ERROR("The infection rate beta must be non-negative in SIR model", IGRAPH_EINVAL);
     }
-    if (gamma < 0) {
-        IGRAPH_ERROR("Gamma must be non-negative in SIR model", IGRAPH_EINVAL);
+    /* With a recovery rate of zero, the simulation would never stop. */
+    if (gamma <= 0) {
+        IGRAPH_ERROR("The recovery rate gamma must be positive in SIR model", IGRAPH_EINVAL);
     }
     if (no_sim <= 0) {
         IGRAPH_ERROR("Number of SIR simulations must be positive", IGRAPH_EINVAL);
     }
 
-    igraph_is_simple(graph, &simple);
+    IGRAPH_CHECK(igraph_is_simple(graph, &simple));
     if (!simple) {
         IGRAPH_ERROR("SIR model only works with simple graphs", IGRAPH_EINVAL);
     }
@@ -156,7 +158,7 @@
         if (!sir) {
             IGRAPH_ERROR("Cannot run SIR model", IGRAPH_ENOMEM);
         }
-        igraph_sir_init(sir);
+        IGRAPH_CHECK(igraph_sir_init(sir));
         VECTOR(*result)[i] = sir;
     }
 
@@ -202,6 +204,8 @@
             igraph_real_t r;
             long int vchange;
 
+            IGRAPH_ALLOW_INTERRUPTION();
+
             psum = igraph_psumtree_sum(&tree);
             tt = igraph_rng_get_exp(igraph_rng_default(), psum);
             r = RNG_UNIF(0, psum);
@@ -235,18 +239,10 @@
                 }
             }
 
-            if (times_v) {
-                igraph_vector_push_back(times_v, tt + igraph_vector_tail(times_v));
-            }
-            if (no_s_v)  {
-                igraph_vector_int_push_back(no_s_v, ns);
-            }
-            if (no_i_v)  {
-                igraph_vector_int_push_back(no_i_v, ni);
-            }
-            if (no_r_v)  {
-                igraph_vector_int_push_back(no_r_v, nr);
-            }
+            IGRAPH_CHECK(igraph_vector_push_back(times_v, tt + igraph_vector_tail(times_v)));
+            IGRAPH_CHECK(igraph_vector_int_push_back(no_s_v, ns));
+            IGRAPH_CHECK(igraph_vector_int_push_back(no_i_v, ni));
+            IGRAPH_CHECK(igraph_vector_int_push_back(no_r_v, nr));
 
         } /* psum > 0 */
 
diff --git a/igraph/src/spanning_trees.c b/igraph/src/spanning_trees.c
--- a/igraph/src/spanning_trees.c
+++ b/igraph/src/spanning_trees.c
@@ -33,10 +33,10 @@
 #include "igraph_progress.h"
 #include "igraph_types_internal.h"
 
-int igraph_i_minimum_spanning_tree_unweighted(const igraph_t *graph,
-        igraph_vector_t *result);
-int igraph_i_minimum_spanning_tree_prim(const igraph_t *graph,
-                                        igraph_vector_t *result, const igraph_vector_t *weights);
+static int igraph_i_minimum_spanning_tree_unweighted(const igraph_t *graph,
+                                                     igraph_vector_t *result);
+static int igraph_i_minimum_spanning_tree_prim(const igraph_t *graph,
+                                               igraph_vector_t *result, const igraph_vector_t *weights);
 
 /**
  * \ingroup structural
@@ -203,8 +203,7 @@
 }
 
 
-int igraph_i_minimum_spanning_tree_unweighted(const igraph_t* graph,
-        igraph_vector_t* res) {
+static int igraph_i_minimum_spanning_tree_unweighted(const igraph_t* graph, igraph_vector_t* res) {
 
     long int no_of_nodes = igraph_vcount(graph);
     long int no_of_edges = igraph_ecount(graph);
@@ -271,8 +270,8 @@
     return IGRAPH_SUCCESS;
 }
 
-int igraph_i_minimum_spanning_tree_prim(const igraph_t* graph,
-                                        igraph_vector_t* res, const igraph_vector_t *weights) {
+static int igraph_i_minimum_spanning_tree_prim(
+        const igraph_t* graph, igraph_vector_t* res, const igraph_vector_t *weights) {
 
     long int no_of_nodes = igraph_vcount(graph);
     long int no_of_edges = igraph_ecount(graph);
diff --git a/igraph/src/sparsemat.c b/igraph/src/sparsemat.c
--- a/igraph/src/sparsemat.c
+++ b/igraph/src/sparsemat.c
@@ -320,10 +320,10 @@
     return 0;
 }
 
-int igraph_i_sparsemat_index_rows(const igraph_sparsemat_t *A,
-                                  const igraph_vector_int_t *p,
-                                  igraph_sparsemat_t *res,
-                                  igraph_real_t *constres) {
+static int igraph_i_sparsemat_index_rows(const igraph_sparsemat_t *A,
+                                         const igraph_vector_int_t *p,
+                                         igraph_sparsemat_t *res,
+                                         igraph_real_t *constres) {
 
     igraph_sparsemat_t II, II2;
     long int nrow = A->cs->m;
@@ -358,10 +358,10 @@
     return 0;
 }
 
-int igraph_i_sparsemat_index_cols(const igraph_sparsemat_t *A,
-                                  const igraph_vector_int_t *q,
-                                  igraph_sparsemat_t *res,
-                                  igraph_real_t *constres) {
+static int igraph_i_sparsemat_index_cols(const igraph_sparsemat_t *A,
+                                         const igraph_vector_int_t *q,
+                                         igraph_sparsemat_t *res,
+                                         igraph_real_t *constres) {
 
     igraph_sparsemat_t JJ, JJ2;
     long int ncol = A->cs->n;
@@ -590,6 +590,7 @@
     return 0;
 }
 
+static
 igraph_bool_t
 igraph_i_sparsemat_is_symmetric_cc(const igraph_sparsemat_t *A) {
     igraph_sparsemat_t t, tt;
@@ -619,6 +620,7 @@
     return res;
 }
 
+static
 igraph_bool_t
 igraph_i_sparsemat_is_symmetric_triplet(const igraph_sparsemat_t *A) {
     igraph_sparsemat_t tmp;
@@ -1048,8 +1050,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_cc(igraph_t *graph, const igraph_sparsemat_t *A,
-                          igraph_bool_t directed) {
+static int igraph_i_sparsemat_cc(igraph_t *graph, const igraph_sparsemat_t *A,
+                                 igraph_bool_t directed) {
 
     igraph_vector_t edges;
     long int no_of_nodes = A->cs->m;
@@ -1088,8 +1090,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_triplet(igraph_t *graph, const igraph_sparsemat_t *A,
-                               igraph_bool_t directed) {
+static int igraph_i_sparsemat_triplet(igraph_t *graph, const igraph_sparsemat_t *A,
+                                      igraph_bool_t directed) {
 
     igraph_vector_t edges;
     long int no_of_nodes = A->cs->m;
@@ -1149,11 +1151,11 @@
     }
 }
 
-int igraph_i_weighted_sparsemat_cc(const igraph_sparsemat_t *A,
-                                   igraph_bool_t directed, const char *attr,
-                                   igraph_bool_t loops,
-                                   igraph_vector_t *edges,
-                                   igraph_vector_t *weights) {
+static int igraph_i_weighted_sparsemat_cc(const igraph_sparsemat_t *A,
+                                          igraph_bool_t directed, const char *attr,
+                                          igraph_bool_t loops,
+                                          igraph_vector_t *edges,
+                                          igraph_vector_t *weights) {
 
     long int no_of_edges = A->cs->p[A->cs->n];
     int *p = A->cs->p;
@@ -1189,12 +1191,12 @@
     return 0;
 }
 
-int igraph_i_weighted_sparsemat_triplet(const igraph_sparsemat_t *A,
-                                        igraph_bool_t directed,
-                                        const char *attr,
-                                        igraph_bool_t loops,
-                                        igraph_vector_t *edges,
-                                        igraph_vector_t *weights) {
+static int igraph_i_weighted_sparsemat_triplet(const igraph_sparsemat_t *A,
+                                               igraph_bool_t directed,
+                                               const char *attr,
+                                               igraph_bool_t loops,
+                                               igraph_vector_t *edges,
+                                               igraph_vector_t *weights) {
 
     IGRAPH_UNUSED(A); IGRAPH_UNUSED(directed); IGRAPH_UNUSED(attr);
     IGRAPH_UNUSED(loops); IGRAPH_UNUSED(edges); IGRAPH_UNUSED(weights);
@@ -1338,8 +1340,8 @@
 
 #undef CHECK
 
-int igraph_i_sparsemat_eye_triplet(igraph_sparsemat_t *A, int n, int nzmax,
-                                   igraph_real_t value) {
+static int igraph_i_sparsemat_eye_triplet(igraph_sparsemat_t *A, int n, int nzmax,
+                                          igraph_real_t value) {
     long int i;
 
     IGRAPH_CHECK(igraph_sparsemat_init(A, n, n, nzmax));
@@ -1351,8 +1353,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_eye_cc(igraph_sparsemat_t *A, int n,
-                              igraph_real_t value) {
+static int igraph_i_sparsemat_eye_cc(igraph_sparsemat_t *A, int n,
+                                     igraph_real_t value) {
     long int i;
 
     if (! (A->cs = cs_spalloc(n, n, n, /*values=*/ 1, /*triplet=*/ 0)) ) {
@@ -1397,8 +1399,8 @@
     }
 }
 
-int igraph_i_sparsemat_diag_triplet(igraph_sparsemat_t *A, int nzmax,
-                                    const igraph_vector_t *values) {
+static int igraph_i_sparsemat_diag_triplet(igraph_sparsemat_t *A, int nzmax,
+                                           const igraph_vector_t *values) {
 
     int i, n = (int) igraph_vector_size(values);
 
@@ -1412,8 +1414,8 @@
 
 }
 
-int igraph_i_sparsemat_diag_cc(igraph_sparsemat_t *A,
-                               const igraph_vector_t *values) {
+static int igraph_i_sparsemat_diag_cc(igraph_sparsemat_t *A,
+                                      const igraph_vector_t *values) {
 
     int i, n = (int) igraph_vector_size(values);
 
@@ -1461,10 +1463,10 @@
     }
 }
 
-int igraph_i_sparsemat_arpack_multiply(igraph_real_t *to,
-                                       const igraph_real_t *from,
-                                       int n,
-                                       void *extra) {
+static int igraph_i_sparsemat_arpack_multiply(igraph_real_t *to,
+                                              const igraph_real_t *from,
+                                              int n,
+                                              void *extra) {
     igraph_sparsemat_t *A = extra;
     igraph_vector_t vto, vfrom;
     igraph_vector_view(&vto, to, n);
@@ -1481,10 +1483,10 @@
     igraph_sparsemat_solve_t method;
 } igraph_i_sparsemat_arpack_rssolve_data_t;
 
-int igraph_i_sparsemat_arpack_solve(igraph_real_t *to,
-                                    const igraph_real_t *from,
-                                    int n,
-                                    void *extra) {
+static int igraph_i_sparsemat_arpack_solve(igraph_real_t *to,
+                                           const igraph_real_t *from,
+                                           int n,
+                                           void *extra) {
 
     igraph_i_sparsemat_arpack_rssolve_data_t *data = extra;
     igraph_vector_t vfrom, vto;
@@ -1958,8 +1960,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_as_matrix_cc(igraph_matrix_t *res,
-                                    const igraph_sparsemat_t *spmat) {
+static int igraph_i_sparsemat_as_matrix_cc(igraph_matrix_t *res,
+                                           const igraph_sparsemat_t *spmat) {
 
     int nrow = (int) igraph_sparsemat_nrow(spmat);
     int ncol = (int) igraph_sparsemat_ncol(spmat);
@@ -1986,8 +1988,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_as_matrix_triplet(igraph_matrix_t *res,
-        const igraph_sparsemat_t *spmat) {
+static int igraph_i_sparsemat_as_matrix_triplet(igraph_matrix_t *res,
+                                                const igraph_sparsemat_t *spmat) {
     int nrow = (int) igraph_sparsemat_nrow(spmat);
     int ncol = (int) igraph_sparsemat_ncol(spmat);
     int *i = spmat->cs->p;
@@ -2201,8 +2203,8 @@
     return res;
 }
 
-int igraph_i_sparsemat_rowsums_triplet(const igraph_sparsemat_t *A,
-                                       igraph_vector_t *res) {
+static int igraph_i_sparsemat_rowsums_triplet(const igraph_sparsemat_t *A,
+                                              igraph_vector_t *res) {
     int i;
     int *pi = A->cs->i;
     double *px = A->cs->x;
@@ -2217,8 +2219,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_rowsums_cc(const igraph_sparsemat_t *A,
-                                  igraph_vector_t *res) {
+static int igraph_i_sparsemat_rowsums_cc(const igraph_sparsemat_t *A,
+                                         igraph_vector_t *res) {
     int ne = A->cs->p[A->cs->n];
     double *px = A->cs->x;
     int *pi = A->cs->i;
@@ -2254,8 +2256,8 @@
     }
 }
 
-int igraph_i_sparsemat_rowmins_triplet(const igraph_sparsemat_t *A,
-                                       igraph_vector_t *res) {
+static int igraph_i_sparsemat_rowmins_triplet(const igraph_sparsemat_t *A,
+                                              igraph_vector_t *res) {
     int i;
     int *pi = A->cs->i;
     double *px = A->cs->x;
@@ -2273,8 +2275,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_rowmins_cc(igraph_sparsemat_t *A,
-                                  igraph_vector_t *res) {
+static int igraph_i_sparsemat_rowmins_cc(igraph_sparsemat_t *A,
+                                         igraph_vector_t *res) {
     int ne;
     double *px;
     int *pi;
@@ -2308,8 +2310,8 @@
 }
 
 
-int igraph_i_sparsemat_rowmaxs_triplet(const igraph_sparsemat_t *A,
-                                       igraph_vector_t *res) {
+static int igraph_i_sparsemat_rowmaxs_triplet(const igraph_sparsemat_t *A,
+                                              igraph_vector_t *res) {
     int i;
     int *pi = A->cs->i;
     double *px = A->cs->x;
@@ -2327,8 +2329,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_rowmaxs_cc(igraph_sparsemat_t *A,
-                                  igraph_vector_t *res) {
+static int igraph_i_sparsemat_rowmaxs_cc(igraph_sparsemat_t *A,
+                                         igraph_vector_t *res) {
     int ne;
     double *px;
     int *pi;
@@ -2361,8 +2363,8 @@
     }
 }
 
-int igraph_i_sparsemat_colmins_triplet(const igraph_sparsemat_t *A,
-                                       igraph_vector_t *res) {
+static int igraph_i_sparsemat_colmins_triplet(const igraph_sparsemat_t *A,
+                                              igraph_vector_t *res) {
     int i;
     int *pp = A->cs->p;
     double *px = A->cs->x;
@@ -2380,8 +2382,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_colmins_cc(igraph_sparsemat_t *A,
-                                  igraph_vector_t *res) {
+static int igraph_i_sparsemat_colmins_cc(igraph_sparsemat_t *A,
+                                         igraph_vector_t *res) {
     int n;
     double *px;
     int *pp;
@@ -2419,8 +2421,8 @@
     }
 }
 
-int igraph_i_sparsemat_colmaxs_triplet(const igraph_sparsemat_t *A,
-                                       igraph_vector_t *res) {
+static int igraph_i_sparsemat_colmaxs_triplet(const igraph_sparsemat_t *A,
+                                              igraph_vector_t *res) {
     int i;
     int *pp = A->cs->p;
     double *px = A->cs->x;
@@ -2438,8 +2440,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_colmaxs_cc(igraph_sparsemat_t *A,
-                                  igraph_vector_t *res) {
+static int igraph_i_sparsemat_colmaxs_cc(igraph_sparsemat_t *A,
+                                         igraph_vector_t *res) {
     int n;
     double *px;
     int *pp;
@@ -2477,9 +2479,9 @@
     }
 }
 
-int igraph_i_sparsemat_which_min_rows_triplet(igraph_sparsemat_t *A,
-        igraph_vector_t *res,
-        igraph_vector_int_t *pos) {
+static int igraph_i_sparsemat_which_min_rows_triplet(igraph_sparsemat_t *A,
+                                                     igraph_vector_t *res,
+                                                     igraph_vector_int_t *pos) {
     int i;
     int *pi = A->cs->i;
     int *pp = A->cs->p;
@@ -2501,9 +2503,9 @@
     return 0;
 }
 
-int igraph_i_sparsemat_which_min_rows_cc(igraph_sparsemat_t *A,
-        igraph_vector_t *res,
-        igraph_vector_int_t *pos) {
+static int igraph_i_sparsemat_which_min_rows_cc(igraph_sparsemat_t *A,
+                                                igraph_vector_t *res,
+                                                igraph_vector_int_t *pos) {
     int n;
     double *px;
     int *pp;
@@ -2545,9 +2547,9 @@
     }
 }
 
-int igraph_i_sparsemat_which_min_cols_triplet(igraph_sparsemat_t *A,
-        igraph_vector_t *res,
-        igraph_vector_int_t *pos) {
+static int igraph_i_sparsemat_which_min_cols_triplet(igraph_sparsemat_t *A,
+                                                     igraph_vector_t *res,
+                                                     igraph_vector_int_t *pos) {
 
     int i;
     int *pi = A->cs->i;
@@ -2570,9 +2572,9 @@
     return 0;
 }
 
-int igraph_i_sparsemat_which_min_cols_cc(igraph_sparsemat_t *A,
-        igraph_vector_t *res,
-        igraph_vector_int_t *pos) {
+static int igraph_i_sparsemat_which_min_cols_cc(igraph_sparsemat_t *A,
+                                                igraph_vector_t *res,
+                                                igraph_vector_int_t *pos) {
     int n, j, p;
     double *px;
     double *pr;
@@ -2612,8 +2614,8 @@
     }
 }
 
-int igraph_i_sparsemat_colsums_triplet(const igraph_sparsemat_t *A,
-                                       igraph_vector_t *res) {
+static int igraph_i_sparsemat_colsums_triplet(const igraph_sparsemat_t *A,
+                                              igraph_vector_t *res) {
     int i;
     int *pp = A->cs->p;
     double *px = A->cs->x;
@@ -2628,8 +2630,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_colsums_cc(const igraph_sparsemat_t *A,
-                                  igraph_vector_t *res) {
+static int igraph_i_sparsemat_colsums_cc(const igraph_sparsemat_t *A,
+                                         igraph_vector_t *res) {
     int n = A->cs->n;
     double *px = A->cs->x;
     int *pp = A->cs->p;
@@ -2828,8 +2830,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_scale_cols_cc(igraph_sparsemat_t *A,
-                                     const igraph_vector_t *fact) {
+static int igraph_i_sparsemat_scale_cols_cc(igraph_sparsemat_t *A,
+                                            const igraph_vector_t *fact) {
     int *i = A->cs->i;
     igraph_real_t *x = A->cs->x;
     int no_of_edges = A->cs->p[A->cs->n];
@@ -2848,8 +2850,8 @@
     return 0;
 }
 
-int igraph_i_sparsemat_scale_cols_triplet(igraph_sparsemat_t *A,
-        const igraph_vector_t *fact) {
+static int igraph_i_sparsemat_scale_cols_triplet(igraph_sparsemat_t *A,
+                                                 const igraph_vector_t *fact) {
     int *j = A->cs->p;
     igraph_real_t *x = A->cs->x;
     int no_of_edges = A->cs->nz;
diff --git a/igraph/src/spectral_properties.c b/igraph/src/spectral_properties.c
--- a/igraph/src/spectral_properties.c
+++ b/igraph/src/spectral_properties.c
@@ -27,10 +27,10 @@
 #include "config.h"
 #include <math.h>
 
-int igraph_i_weighted_laplacian(const igraph_t *graph, igraph_matrix_t *res,
-                                igraph_sparsemat_t *sparseres,
-                                igraph_bool_t normalized,
-                                const igraph_vector_t *weights) {
+static int igraph_i_weighted_laplacian(const igraph_t *graph, igraph_matrix_t *res,
+                                       igraph_sparsemat_t *sparseres,
+                                       igraph_bool_t normalized,
+                                       const igraph_vector_t *weights) {
 
     igraph_eit_t edgeit;
     int no_of_nodes = (int) igraph_vcount(graph);
diff --git a/igraph/src/spmatrix.c b/igraph/src/spmatrix.c
--- a/igraph/src/spmatrix.c
+++ b/igraph/src/spmatrix.c
@@ -24,14 +24,11 @@
 
 #include "igraph_types.h"
 #include "igraph_spmatrix.h"
-#include "igraph_memory.h"
-#include "igraph_random.h"
 #include "igraph_error.h"
 #include "config.h"
 
 #include <assert.h>
 #include <string.h>     /* memcpy & co. */
-#include <stdlib.h>
 
 /**
  * \section igraph_spmatrix_constructor_and_destructor Sparse matrix constructors
diff --git a/igraph/src/st-cuts.c b/igraph/src/st-cuts.c
--- a/igraph/src/st-cuts.c
+++ b/igraph/src/st-cuts.c
@@ -28,18 +28,16 @@
 #include "igraph_constants.h"
 #include "igraph_interface.h"
 #include "igraph_adjlist.h"
-#include "igraph_conversion.h"
 #include "igraph_constructors.h"
 #include "igraph_structural.h"
 #include "igraph_components.h"
-#include "igraph_types_internal.h"
-#include "config.h"
 #include "igraph_math.h"
 #include "igraph_dqueue.h"
 #include "igraph_visitor.h"
 #include "igraph_marked_queue.h"
 #include "igraph_stack.h"
 #include "igraph_estack.h"
+#include "config.h"
 
 /*
  * \function igraph_even_tarjan_reduction
@@ -244,7 +242,7 @@
     igraph_vector_long_t next;
 } igraph_i_dbucket_t;
 
-int igraph_i_dbucket_init(igraph_i_dbucket_t *buck, long int size) {
+static int igraph_i_dbucket_init(igraph_i_dbucket_t *buck, long int size) {
     IGRAPH_CHECK(igraph_vector_long_init(&buck->head, size));
     IGRAPH_FINALLY(igraph_vector_long_destroy, &buck->head);
     IGRAPH_CHECK(igraph_vector_long_init(&buck->next, size));
@@ -252,42 +250,42 @@
     return 0;
 }
 
-void igraph_i_dbucket_destroy(igraph_i_dbucket_t *buck) {
+static void igraph_i_dbucket_destroy(igraph_i_dbucket_t *buck) {
     igraph_vector_long_destroy(&buck->head);
     igraph_vector_long_destroy(&buck->next);
 }
 
-int igraph_i_dbucket_insert(igraph_i_dbucket_t *buck, long int bid,
-                            long int elem) {
+static int igraph_i_dbucket_insert(igraph_i_dbucket_t *buck, long int bid,
+                                   long int elem) {
     /* Note: we can do this, since elem is not in any buckets */
     VECTOR(buck->next)[elem] = VECTOR(buck->head)[bid];
     VECTOR(buck->head)[bid] = elem + 1;
     return 0;
 }
 
-long int igraph_i_dbucket_empty(const igraph_i_dbucket_t *buck,
-                                long int bid) {
+static long int igraph_i_dbucket_empty(const igraph_i_dbucket_t *buck,
+                                       long int bid) {
     return VECTOR(buck->head)[bid] == 0;
 }
 
-long int igraph_i_dbucket_delete(igraph_i_dbucket_t *buck, long int bid) {
+static long int igraph_i_dbucket_delete(igraph_i_dbucket_t *buck, long int bid) {
     long int elem = VECTOR(buck->head)[bid] - 1;
     VECTOR(buck->head)[bid] = VECTOR(buck->next)[elem];
     return elem;
 }
 
-int igraph_i_dominator_LINK(long int v, long int w,
-                            igraph_vector_long_t *ancestor) {
+static int igraph_i_dominator_LINK(long int v, long int w,
+                                   igraph_vector_long_t *ancestor) {
     VECTOR(*ancestor)[w] = v + 1;
     return 0;
 }
 
 /* TODO: don't always reallocate path */
 
-int igraph_i_dominator_COMPRESS(long int v,
-                                igraph_vector_long_t *ancestor,
-                                igraph_vector_long_t *label,
-                                igraph_vector_long_t *semi) {
+static int igraph_i_dominator_COMPRESS(long int v,
+                                       igraph_vector_long_t *ancestor,
+                                       igraph_vector_long_t *label,
+                                       igraph_vector_long_t *semi) {
     igraph_stack_long_t path;
     long int w = v;
     long int top, pretop;
@@ -319,10 +317,10 @@
     return 0;
 }
 
-long int igraph_i_dominator_EVAL(long int v,
-                                 igraph_vector_long_t *ancestor,
-                                 igraph_vector_long_t *label,
-                                 igraph_vector_long_t *semi) {
+static long int igraph_i_dominator_EVAL(long int v,
+                                        igraph_vector_long_t *ancestor,
+                                        igraph_vector_long_t *label,
+                                        igraph_vector_long_t *semi) {
     if (VECTOR(*ancestor)[v] == 0) {
         return v;
     } else {
@@ -362,7 +360,7 @@
  * \param dom Pointer to an initialized vector or a null pointer. If
  *        not a null pointer, then the immediate dominator of each
  *        vertex will be stored here. For vertices that are not
- *        reachable from the root, \c IGRAPH_NAN is stored here. For
+ *        reachable from the root, NaN is stored here. For
  *        the root vertex itself, -1 is added.
  * \param domtree Pointer to an uninitialized igraph_t, or NULL. If
  *        not a null pointer, then the dominator tree is returned
@@ -579,7 +577,8 @@
     const igraph_vector_t *map;
 } igraph_i_all_st_cuts_minimal_dfs_data_t;
 
-igraph_bool_t igraph_i_all_st_cuts_minimal_dfs_incb(const igraph_t *graph,
+static igraph_bool_t igraph_i_all_st_cuts_minimal_dfs_incb(
+        const igraph_t *graph,
         igraph_integer_t vid,
         igraph_integer_t dist,
         void *extra) {
@@ -604,7 +603,8 @@
     return 0;
 }
 
-igraph_bool_t igraph_i_all_st_cuts_minimal_dfs_otcb(const igraph_t *graph,
+static igraph_bool_t igraph_i_all_st_cuts_minimal_dfs_otcb(
+        const igraph_t *graph,
         igraph_integer_t vid,
         igraph_integer_t dist,
         void *extra) {
@@ -623,13 +623,13 @@
     return 0;
 }
 
-int igraph_i_all_st_cuts_minimal(const igraph_t *graph,
-                                 const igraph_t *domtree,
-                                 long int root,
-                                 const igraph_marked_queue_t *X,
-                                 const igraph_vector_bool_t *GammaX,
-                                 const igraph_vector_t *invmap,
-                                 igraph_vector_t *minimal) {
+static int igraph_i_all_st_cuts_minimal(const igraph_t *graph,
+                                        const igraph_t *domtree,
+                                        long int root,
+                                        const igraph_marked_queue_t *X,
+                                        const igraph_vector_bool_t *GammaX,
+                                        const igraph_vector_t *invmap,
+                                        igraph_vector_t *minimal) {
 
     long int no_of_nodes = igraph_vcount(graph);
     igraph_stack_t stack;
@@ -684,6 +684,7 @@
     return 0;
 }
 
+/* not 'static' because used in igraph_all_st_cuts.c test program */
 int igraph_i_all_st_cuts_pivot(const igraph_t *graph,
                                const igraph_marked_queue_t *S,
                                const igraph_estack_t *T,
@@ -1118,10 +1119,10 @@
    zero-indegree vertices.
 */
 
-int igraph_i_all_st_mincuts_minimal(const igraph_t *Sbar,
-                                    const igraph_vector_bool_t *active,
-                                    const igraph_vector_t *invmap,
-                                    igraph_vector_t *minimal) {
+static int igraph_i_all_st_mincuts_minimal(const igraph_t *Sbar,
+                                           const igraph_vector_bool_t *active,
+                                           const igraph_vector_t *invmap,
+                                           igraph_vector_t *minimal) {
 
     long int no_of_nodes = igraph_vcount(Sbar);
     igraph_vector_t indeg;
@@ -1169,7 +1170,7 @@
 
     igraph_vector_destroy(&indeg);
     igraph_vector_destroy(&neis);
-    IGRAPH_FINALLY_CLEAN(3);
+    IGRAPH_FINALLY_CLEAN(2);
 
     return 0;
 }
@@ -1178,14 +1179,14 @@
     const igraph_vector_bool_t *active;
 } igraph_i_all_st_mincuts_data_t;
 
-int igraph_i_all_st_mincuts_pivot(const igraph_t *graph,
-                                  const igraph_marked_queue_t *S,
-                                  const igraph_estack_t *T,
-                                  long int source,
-                                  long int target,
-                                  long int *v,
-                                  igraph_vector_t *Isv,
-                                  void *arg) {
+static int igraph_i_all_st_mincuts_pivot(const igraph_t *graph,
+                                         const igraph_marked_queue_t *S,
+                                         const igraph_estack_t *T,
+                                         long int source,
+                                         long int target,
+                                         long int *v,
+                                         igraph_vector_t *Isv,
+                                         void *arg) {
 
     igraph_i_all_st_mincuts_data_t *data = arg;
     const igraph_vector_bool_t *active = data->active;
@@ -1283,10 +1284,14 @@
  * \function igraph_all_st_mincuts
  * All minimum s-t cuts of a directed graph
  *
- * This function lists all minimum edge cuts between two vertices, in a
- * directed graph. The implemented algorithm
- * is described in JS Provan and DR Shier: A Paradigm for listing
- * (s,t)-cuts in graphs, Algorithmica 15, 351--372, 1996.
+ * This function lists all edge cuts between two vertices, in a directed graph,
+ * with minimum total capacity. Possibly, multiple cuts may have the same total
+ * capacity, although there is often only one minimum cut in weighted graphs.
+ * It is recommended to supply integer-values capacities. Otherwise, not all
+ * minimum cuts may be detected because of numerical roundoff errors.
+ * The implemented algorithm is described in JS Provan and DR
+ * Shier: A Paradigm for listing (s,t)-cuts in graphs, Algorithmica 15,
+ * 351--372, 1996.
  *
  * \param graph The input graph, it must be directed.
  * \param value Pointer to a real number, the value of the minimum cut
@@ -1306,8 +1311,9 @@
  *        ignored if it is a null pointer.
  * \param source The id of the source vertex.
  * \param target The id of the target vertex.
- * \param capacity Vector of edge capacities. If this is a null
- *        pointer, then all edges are assumed to have capacity one.
+ * \param capacity Vector of edge capacities. All capacities must be
+ *        strictly positive. If this is a null pointer, then all edges
+ *        are assumed to have capacity one.
  * \return Error code.
  *
  * Time complexity: O(n(|V|+|E|))+O(F), where |V| is the number of
@@ -1358,6 +1364,10 @@
     }
     if (source == target) {
         IGRAPH_ERROR("`source' and 'target' are the same vertex", IGRAPH_EINVAL);
+    }
+    if (capacity != NULL && igraph_vector_min(capacity) <= 0)
+    {
+        IGRAPH_ERROR("Not all capacities are strictly positive.", IGRAPH_EINVAL);
     }
 
     if (!partition1s) {
diff --git a/igraph/src/statusbar.c b/igraph/src/statusbar.c
--- a/igraph/src/statusbar.c
+++ b/igraph/src/statusbar.c
@@ -21,10 +21,10 @@
 
 */
 
-#include "config.h"
 #include "igraph_types.h"
 #include "igraph_statusbar.h"
 #include "igraph_error.h"
+#include "config.h"
 #include <stdio.h>
 #include <stdarg.h>
 
diff --git a/igraph/src/structural_properties.c b/igraph/src/structural_properties.c
--- a/igraph/src/structural_properties.c
+++ b/igraph/src/structural_properties.c
@@ -1554,7 +1554,7 @@
 }
 
 /* Not declared static so that the testsuite can use it, but not part of the public API. */
-int igraph_rewire_core(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode, igraph_bool_t use_adjlist) {
+int igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode, igraph_bool_t use_adjlist) {
     long int no_of_nodes = igraph_vcount(graph);
     long int no_of_edges = igraph_ecount(graph);
     char message[256];
@@ -1785,7 +1785,7 @@
 int igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode) {
 
     igraph_bool_t use_adjlist = n >= REWIRE_ADJLIST_THRESHOLD;
-    return igraph_rewire_core(graph, n, mode, use_adjlist);
+    return igraph_i_rewire(graph, n, mode, use_adjlist);
 
 }
 
@@ -1915,11 +1915,13 @@
     for (i = 0; i < no_of_new_nodes; i++) {
         long int old_vid = (long int) VECTOR(*my_vids_new2old)[i];
         long int new_vid = i;
+        igraph_bool_t skip_loop_edge;
 
         IGRAPH_CHECK(igraph_incident(graph, &nei_edges, old_vid, IGRAPH_OUT));
         n = igraph_vector_size(&nei_edges);
 
         if (directed) {
+            /* directed graph; this is easier */
             for (j = 0; j < n; j++) {
                 eid = (igraph_integer_t) VECTOR(nei_edges)[j];
 
@@ -1933,10 +1935,15 @@
                 IGRAPH_CHECK(igraph_vector_push_back(&eids_new2old, eid));
             }
         } else {
+            /* undirected graph. We need to be careful with loop edges as each
+             * loop edge will appear twice. We use a boolean flag to skip every
+             * second loop edge */
+            skip_loop_edge = 0;
             for (j = 0; j < n; j++) {
                 eid = (igraph_integer_t) VECTOR(nei_edges)[j];
 
-                if (IGRAPH_FROM(graph, eid) != old_vid) { /* avoid processing edges twice */
+                if (IGRAPH_FROM(graph, eid) != old_vid) {
+                    /* avoid processing edges twice */
                     continue;
                 }
 
@@ -1944,9 +1951,18 @@
                 if (!to) {
                     continue;
                 }
+                to -= 1;
 
+                if (new_vid == to) {
+                    /* this is a loop edge; check whether we need to skip it */
+                    skip_loop_edge = !skip_loop_edge;
+                    if (skip_loop_edge) {
+                        continue;
+                    }
+                }
+
                 IGRAPH_CHECK(igraph_vector_push_back(&new_edges, new_vid));
-                IGRAPH_CHECK(igraph_vector_push_back(&new_edges, to - 1));
+                IGRAPH_CHECK(igraph_vector_push_back(&new_edges, to));
                 IGRAPH_CHECK(igraph_vector_push_back(&eids_new2old, eid));
             }
         }
@@ -2540,7 +2556,7 @@
  * C[i] = sum( sum( (p[i,q] p[q,j])^2, q in V[i], q != i,j ), j in
  * V[], j != i)
  * </para></blockquote>
- * for a graph of order (ie. number of vertices) N, where proportional
+ * for a graph of order (i.e. number of vertices) N, where proportional
  * tie strengths are defined as
  * <blockquote><para>
  * p[i,j]=(a[i,j]+a[j,i]) / sum(a[i,k]+a[k,i], k in V[i], k != i),
@@ -2948,7 +2964,7 @@
  * \brief Calculates the size of the neighborhood of a given vertex.
  *
  * The neighborhood of a given order of a vertex includes all vertices
- * which are closer to the vertex than the order. Ie. order 0 is
+ * which are closer to the vertex than the order. I.e., order 0 is
  * always the vertex itself, order 1 is the vertex plus its immediate
  * neighbors, order 2 is order 1 plus the immediate neighbors of the
  * vertices in order 1, etc.
@@ -3074,7 +3090,7 @@
  * Calculate the neighborhood of vertices.
  *
  * The neighborhood of a given order of a vertex includes all vertices
- * which are closer to the vertex than the order. Ie. order 0 is
+ * which are closer to the vertex than the order. I.e., order 0 is
  * always the vertex itself, order 1 is the vertex plus its immediate
  * neighbors, order 2 is order 1 plus the immediate neighbors of the
  * vertices in order 1, etc.
@@ -3085,15 +3101,15 @@
  * \param res An initialized pointer vector. Note that the objects
  *    (pointers) in the vector will \em not be freed, but the pointer
  *    vector will be resized as needed. The result of the calculation
- *    will be stored here in \c vector_t objects.
+ *    will be stored here in \ref igraph_vector_t objects.
  * \param vids The vertices for which the calculation is performed.
  * \param order Integer giving the order of the neighborhood.
  * \param mode Specifies how to use the direction of the edges if a
  *   directed graph is analyzed. For \c IGRAPH_OUT only the outgoing
  *   edges are followed, so all vertices reachable from the source
- *   vertex in at most \c order steps are included. For \c IGRAPH_IN
+ *   vertex in at most \p order steps are included. For \c IGRAPH_IN
  *   all vertices from which the source vertex is reachable in at most
- *   \c order steps are included. \c IGRAPH_ALL ignores the direction
+ *   \p order steps are included. \c IGRAPH_ALL ignores the direction
  *   of the edges. This argument is ignored for undirected graphs.
  * \param mindist The minimum distance to include a vertex in the counting.
  *   If this is one, then the starting vertex is not counted. If this is
@@ -3228,7 +3244,7 @@
  * Vincent Matossian, thanks Vincent.
  * \param graph The input graph.
  * \param res Pointer to a pointer vector, the result will be stored
- *   here, ie. \c res will contain pointers to \c igraph_t
+ *   here, ie. \p res will contain pointers to \c igraph_t
  *   objects. It will be resized if needed but note that the
  *   objects in the pointer vector will not be freed.
  * \param vids The vertices for which the calculation is performed.
@@ -3236,9 +3252,9 @@
  * \param mode Specifies how to use the direction of the edges if a
  *   directed graph is analyzed. For \c IGRAPH_OUT only the outgoing
  *   edges are followed, so all vertices reachable from the source
- *   vertex in at most \c order steps are counted. For \c IGRAPH_IN
+ *   vertex in at most \p order steps are counted. For \c IGRAPH_IN
  *   all vertices from which the source vertex is reachable in at most
- *   \c order steps are counted. \c IGRAPH_ALL ignores the direction
+ *   \p order steps are counted. \c IGRAPH_ALL ignores the direction
  *   of the edges. This argument is ignored for undirected graphs.
  * \param mindist The minimum distance to include a vertex in the counting.
  *   If this is one, then the starting vertex is not counted. If this is
@@ -3568,7 +3584,7 @@
         igraph_bool_t found = 0;
         IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
         for (i = 0; i < vc; i++) {
-            igraph_neighbors(graph, &neis, (igraph_integer_t) i, IGRAPH_OUT);
+            IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, IGRAPH_OUT));
             n = igraph_vector_size(&neis);
             for (j = 0; j < n; j++) {
                 if (VECTOR(neis)[j] == i) {
@@ -3781,6 +3797,7 @@
     return 0;
 }
 
+
 /**
  * \function igraph_count_multiple
  * \brief Count the number of appearances of the edges in a graph.
@@ -3801,15 +3818,15 @@
  *
  * \sa \ref igraph_is_multiple() and \ref igraph_simplify().
  *
- * Time complexity: O(e*d), e is the number of edges to check and d is the
+ * Time complexity: O(E d), E is the number of edges to check and d is the
  * average degree (out-degree in directed graphs) of the vertices at the
  * tail of the edges.
  */
 
-
 int igraph_count_multiple(const igraph_t *graph, igraph_vector_t *res, igraph_es_t es) {
     igraph_eit_t eit;
     long int i;
+    igraph_bool_t directed = igraph_is_directed(graph);
     igraph_lazy_inclist_t inclist;
 
     IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
@@ -3835,7 +3852,7 @@
             }
         }
         /* for loop edges, divide the result by two */
-        if (to == from) {
+        if (!directed && to == from) {
             VECTOR(*res)[i] /= 2;
         }
     }
@@ -3843,9 +3860,11 @@
     igraph_lazy_inclist_destroy(&inclist);
     igraph_eit_destroy(&eit);
     IGRAPH_FINALLY_CLEAN(2);
-    return 0;
+
+    return IGRAPH_SUCCESS;
 }
 
+
 /**
  * \function igraph_girth
  * \brief The girth of a graph is the length of the shortest circle in it.
@@ -5968,6 +5987,10 @@
         }
     }
 
+    igraph_vector_destroy(&edge_neis);
+    igraph_vector_destroy(&neis);
+    IGRAPH_FINALLY_CLEAN(2);
+
     if (knnk) {
         for (i = 0; i < maxdeg; i++) {
             igraph_real_t dh = VECTOR(deghist)[i];
@@ -5982,7 +6005,7 @@
         IGRAPH_FINALLY_CLEAN(1);
     }
 
-    igraph_vector_destroy(&neis);
+    igraph_vector_destroy(&strength);
     igraph_vector_destroy(&deg);
     IGRAPH_FINALLY_CLEAN(2);
 
@@ -5999,39 +6022,54 @@
 
 /**
  * \function igraph_avg_nearest_neighbor_degree
- * Average nearest neighbor degree.
+ * Average neighbor degree.
  *
- * Calculates the average degree of the neighbors for each vertex, and
- * optionally, the same quantity in the function of vertex degree.
+ * Calculates the average degree of the neighbors for each vertex (\p knn), and
+ * optionally, the same quantity as a function of the vertex degree (\p knnk).
  *
- * </para><para>For isolate vertices \p knn is set to \c
- * IGRAPH_NAN. The same is done in \p knnk for vertex degrees that
+ * </para><para>
+ * For isolated vertices \p knn is set to NaN.
+ * The same is done in \p knnk for vertex degrees that
  * don't appear in the graph.
  *
- * \param graph The input graph, it can be directed but the
- *   directedness of the edges is ignored.
+ * </para><para>
+ * The weighted version computes a weighted average of the neighbor degrees as
+ *
+ * <code>k_nn_u = 1/s_u sum_v w_uv k_v</code>,
+ *
+ * where <code>s_u = sum_v w_uv</code> is the sum of the incident edge weights
+ * of vertex \c u, i.e. its strength.
+ * The sum runs over the neighbors \c v of vertex \c u
+ * as indicated by \p mode. <code>w_uv</code> denotes the weighted adjacency matrix
+ * and <code>k_v</code> is the neighbors' degree, specified by \p neighbor_degree_mode.
+ *
+ * </para><para>
+ * Reference:
+ * A. Barrat, M. Barthélemy, R. Pastor-Satorras, and A. Vespignani,
+ * The architecture of complex weighted networks,
+ * Proc. Natl. Acad. Sci. USA 101, 3747 (2004).
+ * https://dx.doi.org/10.1073/pnas.0400087101
+ *
+ * \param graph The input graph. It may be directed.
  * \param vids The vertices for which the calculation is performed.
- * \param mode The neighbors over which is averaged.
- * \param neighbor_degree_mode The degree of the neighbors which is
- *   averaged.
+ * \param mode The type of neighbors to consider in directed graphs.
+ *   \c IGRAPH_OUT considers out-neighbors, \c IGRAPH_IN in-neighbors
+ *   and \c IGRAPH_ALL ignores edge directions.
+ * \param neighbor_degree_mode The type of degree to average in directed graphs.
+ *   \c IGRAPH_OUT averages out-degrees, \c IGRAPH_IN averages in-degrees
+ *   and \c IGRAPH_ALL ignores edge directions for the degree calculation.
  * \param vids The vertices for which the calculation is performed.
  * \param knn Pointer to an initialized vector, the result will be
- *   stored here. It will be resized as needed. Supply a NULL pointer
+ *   stored here. It will be resized as needed. Supply a \c NULL pointer
  *   here, if you only want to calculate \c knnk.
- * \param knnk Pointer to an initialized vector, the average nearest
- *   neighbor degree in the function of vertex degree is stored
+ * \param knnk Pointer to an initialized vector, the average
+ *   neighbor degree as a function of the vertex degree is stored
  *   here. The first (zeroth) element is for degree one vertices,
- *   etc. Supply a NULL pointer here if you don't want to calculate
+ *   etc. Supply a \c NULL pointer here if you don't want to calculate
  *   this.
  * \param weights Optional edge weights. Supply a null pointer here
- *   for the non-weighted version. The weighted version computes
- *   a weighted average of the neighbor degrees, i.e.
- *
- *    k_nn_i = 1/s_i sum_j w_ij k_j
+ *   for the non-weighted version.
  *
- *   where s_i is the sum of the weights, the sum runs over
- *   the neighbors as indicated by \c mode (with appropriate weights)
- *   and k_j is the degree, specified by \c neighbor_degree_mode.
  * \return Error code.
  *
  * Time complexity: O(|V|+|E|), linear in the number of vertices and
@@ -6493,8 +6531,7 @@
 
 int igraph_contract_vertices(igraph_t *graph,
                              const igraph_vector_t *mapping,
-                             const igraph_attribute_combination_t
-                             *vertex_comb) {
+                             const igraph_attribute_combination_t *vertex_comb) {
     igraph_vector_t edges;
     long int no_of_nodes = igraph_vcount(graph);
     long int no_of_edges = igraph_ecount(graph);
@@ -6907,15 +6944,22 @@
     }
 }
 
-int igraph_i_is_graphical_degree_sequence_undirected(
-    const igraph_vector_t *degrees, igraph_bool_t *res) {
+int igraph_i_is_graphical_degree_sequence_undirected(const igraph_vector_t *degrees, igraph_bool_t *res) {
     igraph_vector_t work;
     long int w, b, s, c, n, k;
 
+    n = igraph_vector_size(degrees);
+
+    /* zero-length sequences are considered graphical */
+    if (n == 0) {
+        *res = 1;
+        return IGRAPH_SUCCESS;
+    }
+
     IGRAPH_CHECK(igraph_vector_copy(&work, degrees));
     IGRAPH_FINALLY(igraph_vector_destroy, &work);
 
-    igraph_vector_sort(&work);
+    igraph_vector_reverse_sort(&work);
 
     /* This algorithm is outlined in TR-2011-11 of the Egervary Research Group,
      * ISSN 1587-4451. The main loop of the algorithm is O(n) but it is dominated
@@ -6926,13 +6970,12 @@
      * the degrees themselves. w and k are zero-based here; in the technical
      * report they are 1-based */
     *res = 1;
-    n = igraph_vector_size(&work);
     w = n - 1; b = 0; s = 0; c = 0;
     for (k = 0; k < n; k++) {
-        b += VECTOR(*degrees)[k];
+        b += VECTOR(work)[k];
         c += w;
-        while (w > k && VECTOR(*degrees)[w] <= k + 1) {
-            s += VECTOR(*degrees)[w];
+        while (w > k && VECTOR(work)[w] <= k + 1) {
+            s += VECTOR(work)[w];
             c -= (k + 1);
             w--;
         }
@@ -6948,7 +6991,7 @@
     igraph_vector_destroy(&work);
     IGRAPH_FINALLY_CLEAN(1);
 
-    return 0;
+    return IGRAPH_SUCCESS;
 }
 
 typedef struct {
diff --git a/igraph/src/structure_generators.c b/igraph/src/structure_generators.c
--- a/igraph/src/structure_generators.c
+++ b/igraph/src/structure_generators.c
@@ -100,18 +100,18 @@
     return 0;
 }
 
-int igraph_i_adjacency_directed(igraph_matrix_t *adjmatrix,
-                                igraph_vector_t *edges);
-int igraph_i_adjacency_max(igraph_matrix_t *adjmatrix,
-                           igraph_vector_t *edges);
-int igraph_i_adjacency_upper(igraph_matrix_t *adjmatrix,
-                             igraph_vector_t *edges);
-int igraph_i_adjacency_lower(igraph_matrix_t *adjmatrix,
-                             igraph_vector_t *edges);
-int igraph_i_adjacency_min(igraph_matrix_t *adjmatrix,
-                           igraph_vector_t *edges);
+static int igraph_i_adjacency_directed(igraph_matrix_t *adjmatrix,
+                                       igraph_vector_t *edges);
+static int igraph_i_adjacency_max(igraph_matrix_t *adjmatrix,
+                                  igraph_vector_t *edges);
+static int igraph_i_adjacency_upper(igraph_matrix_t *adjmatrix,
+                                    igraph_vector_t *edges);
+static int igraph_i_adjacency_lower(igraph_matrix_t *adjmatrix,
+                                    igraph_vector_t *edges);
+static int igraph_i_adjacency_min(igraph_matrix_t *adjmatrix,
+                                  igraph_vector_t *edges);
 
-int igraph_i_adjacency_directed(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+static int igraph_i_adjacency_directed(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j, k;
@@ -129,7 +129,7 @@
     return 0;
 }
 
-int igraph_i_adjacency_max(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+static int igraph_i_adjacency_max(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j, k;
@@ -151,7 +151,7 @@
     return 0;
 }
 
-int igraph_i_adjacency_upper(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+static int igraph_i_adjacency_upper(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j, k;
@@ -168,7 +168,7 @@
     return 0;
 }
 
-int igraph_i_adjacency_lower(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+static int igraph_i_adjacency_lower(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j, k;
@@ -185,7 +185,7 @@
     return 0;
 }
 
-int igraph_i_adjacency_min(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
+static int igraph_i_adjacency_min(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j, k;
@@ -311,32 +311,39 @@
     return 0;
 }
 
-int igraph_i_weighted_adjacency_directed(const igraph_matrix_t *adjmatrix,
+static int igraph_i_weighted_adjacency_directed(
+        const igraph_matrix_t *adjmatrix,
         igraph_vector_t *edges,
         igraph_vector_t *weights,
         igraph_bool_t loops);
-int igraph_i_weighted_adjacency_plus(const igraph_matrix_t *adjmatrix,
-                                     igraph_vector_t *edges,
-                                     igraph_vector_t *weights,
-                                     igraph_bool_t loops);
-int igraph_i_weighted_adjacency_max(const igraph_matrix_t *adjmatrix,
-                                    igraph_vector_t *edges,
-                                    igraph_vector_t *weights,
-                                    igraph_bool_t loops);
-int igraph_i_weighted_adjacency_upper(const igraph_matrix_t *adjmatrix,
-                                      igraph_vector_t *edges,
-                                      igraph_vector_t *weights,
-                                      igraph_bool_t loops);
-int igraph_i_weighted_adjacency_lower(const igraph_matrix_t *adjmatrix,
-                                      igraph_vector_t *edges,
-                                      igraph_vector_t *weights,
-                                      igraph_bool_t loops);
-int igraph_i_weighted_adjacency_min(const igraph_matrix_t *adjmatrix,
-                                    igraph_vector_t *edges,
-                                    igraph_vector_t *weights,
-                                    igraph_bool_t loops);
+static int igraph_i_weighted_adjacency_plus(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops);
+static int igraph_i_weighted_adjacency_max(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops);
+static int igraph_i_weighted_adjacency_upper(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops);
+static int igraph_i_weighted_adjacency_lower(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops);
+static int igraph_i_weighted_adjacency_min(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops);
 
-int igraph_i_weighted_adjacency_directed(const igraph_matrix_t *adjmatrix,
+static int igraph_i_weighted_adjacency_directed(
+        const igraph_matrix_t *adjmatrix,
         igraph_vector_t *edges,
         igraph_vector_t *weights,
         igraph_bool_t loops) {
@@ -362,10 +369,11 @@
     return 0;
 }
 
-int igraph_i_weighted_adjacency_plus(const igraph_matrix_t *adjmatrix,
-                                     igraph_vector_t *edges,
-                                     igraph_vector_t *weights,
-                                     igraph_bool_t loops) {
+static int igraph_i_weighted_adjacency_plus(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j;
@@ -391,10 +399,11 @@
     return 0;
 }
 
-int igraph_i_weighted_adjacency_max(const igraph_matrix_t *adjmatrix,
-                                    igraph_vector_t *edges,
-                                    igraph_vector_t *weights,
-                                    igraph_bool_t loops) {
+static int igraph_i_weighted_adjacency_max(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j;
@@ -420,10 +429,11 @@
     return 0;
 }
 
-int igraph_i_weighted_adjacency_upper(const igraph_matrix_t *adjmatrix,
-                                      igraph_vector_t *edges,
-                                      igraph_vector_t *weights,
-                                      igraph_bool_t loops) {
+static int igraph_i_weighted_adjacency_upper(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j;
@@ -445,10 +455,11 @@
     return 0;
 }
 
-int igraph_i_weighted_adjacency_lower(const igraph_matrix_t *adjmatrix,
-                                      igraph_vector_t *edges,
-                                      igraph_vector_t *weights,
-                                      igraph_bool_t loops) {
+static int igraph_i_weighted_adjacency_lower(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j;
@@ -470,10 +481,11 @@
     return 0;
 }
 
-int igraph_i_weighted_adjacency_min(const igraph_matrix_t *adjmatrix,
-                                    igraph_vector_t *edges,
-                                    igraph_vector_t *weights,
-                                    igraph_bool_t loops) {
+static int igraph_i_weighted_adjacency_min(
+        const igraph_matrix_t *adjmatrix,
+        igraph_vector_t *edges,
+        igraph_vector_t *weights,
+        igraph_bool_t loops) {
 
     long int no_of_nodes = igraph_matrix_nrow(adjmatrix);
     long int i, j;
@@ -750,18 +762,31 @@
 /**
  * \ingroup generators
  * \function igraph_lattice
- * \brief Creates most kinds of lattices.
+ * \brief Arbitrary dimensional square lattices.
  *
+ * Creates d-dimensional square lattices of the given size. Optionally,
+ * the lattice can be made periodic, and the neighbors within a given
+ * graph distance can be connected.
+ *
+ * </para><para>
+ * In the zero-dimensional case, the singleton graph is returned.
+ *
+ * </para><para>
+ * The vertices of the resulting graph are ordered such that the
+ * index of the vertex at position <code>(i_0, i_1, i_2, ..., i_d)</code>
+ * in a lattice of size <code>(n_0, n_1, ..., n_d)</code> will be
+ * <code>i_0 + n_0 * i_1 + n_0 * n_1 * i_2 + ...</code>.
+ *
  * \param graph An uninitialized graph object.
  * \param dimvector Vector giving the sizes of the lattice in each of
- *        its dimensions. Ie. the dimension of the lattice will be the
+ *        its dimensions. The dimension of the lattice will be the
  *        same as the length of this vector.
  * \param nei Integer value giving the distance (number of steps)
  *        within which two vertices will be connected.
- * \param directed Boolean, whether to create a directed graph. The
- *        direction of the edges is determined by the generation
- *        algorithm and is unlikely to suit you, so this isn't a very
- *        useful option.
+ * \param directed Boolean, whether to create a directed graph. 
+ *        If the \c mutual and \c circular arguments are not set to true,
+ *        edges will be directed from lower-index vertices towards
+ *        higher-index ones.
  * \param mutual Boolean, if the graph is directed this gives whether
  *        to create all connections as mutual.
  * \param circular Boolean, defines whether the generated lattice is
@@ -770,10 +795,10 @@
  *         \c IGRAPH_EINVAL: invalid (negative)
  *         dimension vector.
  *
- * Time complexity: if \p nei is less than two then it is O(|V|+|E|) (as
+ * Time complexity: If \p nei is less than two then it is O(|V|+|E|) (as
  * far as I remember), |V| and |E| are the number of vertices
- * and edges in the generated graph. Otherwise it is O(|V|*d^o+|E|), d
- * is the average degree of the graph, o is the \p nei argument.
+ * and edges in the generated graph. Otherwise it is O(|V|*d^k+|E|), d
+ * is the average degree of the graph, k is the \p nei argument.
  */
 int igraph_lattice(igraph_t *graph, const igraph_vector_t *dimvector,
                    igraph_integer_t nei, igraph_bool_t directed, igraph_bool_t mutual,
@@ -794,14 +819,14 @@
 
     coords = igraph_Calloc(dims, long int);
     if (coords == 0) {
-        IGRAPH_ERROR("lattice failed", IGRAPH_ENOMEM);
+        IGRAPH_ERROR("Lattice creation failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, coords); /* TODO: hack */
+    IGRAPH_FINALLY(igraph_free, coords);
     weights = igraph_Calloc(dims, long int);
     if (weights == 0) {
-        IGRAPH_ERROR("lattice failed", IGRAPH_ENOMEM);
+        IGRAPH_ERROR("Lattice creation failed", IGRAPH_ENOMEM);
     }
-    IGRAPH_FINALLY(free, weights);
+    IGRAPH_FINALLY(igraph_free, weights);
     if (dims > 0) {
         weights[0] = 1;
         for (i = 1; i < dims; i++) {
@@ -1991,9 +2016,7 @@
     32, 33
 };
 
-int igraph_i_famous(igraph_t *graph, const igraph_real_t *data);
-
-int igraph_i_famous(igraph_t *graph, const igraph_real_t *data) {
+static int igraph_i_famous(igraph_t *graph, const igraph_real_t *data) {
     long int no_of_nodes = (long int) data[0];
     long int no_of_edges = (long int) data[1];
     igraph_bool_t directed = (igraph_bool_t) data[2];
@@ -2110,11 +2133,11 @@
  *           vertices and 12 edges.
  *   \cli Petersen
  *           A 3-regular graph with 10 vertices and 15 edges. It is
- *           the smallest hypohamiltonian graph, ie. it is
+ *           the smallest hypohamiltonian graph, i.e. it is
  *           non-hamiltonian but removing any single vertex from it makes it
  *           Hamiltonian.
  *   \cli Robertson
- *           The unique (4,5)-cage graph, ie. a 4-regular
+ *           The unique (4,5)-cage graph, i.e. a 4-regular
  *           graph of girth 5. It has 19 vertices and 38 edges.
  *   \cli Smallestcyclicgroup
  *           A smallest nontrivial graph
@@ -2370,7 +2393,7 @@
  *             invalid Pr&uuml;fer sequence given
  *          \endclist
  *
- * \sa \ref igraph_tree(), \ref igraph_tree_game()
+ * \sa \ref igraph_to_prufer(), \ref igraph_tree(), \ref igraph_tree_game()
  *
  */
 
diff --git a/igraph/src/sugiyama.c b/igraph/src/sugiyama.c
--- a/igraph/src/sugiyama.c
+++ b/igraph/src/sugiyama.c
@@ -22,7 +22,7 @@
 
 */
 
-#include "config.h"
+#include "igraph_layout.h"
 #include "igraph_centrality.h"
 #include "igraph_components.h"
 #include "igraph_constants.h"
@@ -34,6 +34,7 @@
 #include "igraph_memory.h"
 #include "igraph_structural.h"
 #include "igraph_types.h"
+#include "config.h"
 
 #include <limits.h>
 
@@ -157,8 +158,8 @@
 /**
  * Initializes a layering.
  */
-int igraph_i_layering_init(igraph_i_layering_t* layering,
-                           const igraph_vector_t* membership) {
+static int igraph_i_layering_init(igraph_i_layering_t* layering,
+                                  const igraph_vector_t* membership) {
     long int i, n, num_layers;
 
     if (igraph_vector_size(membership) == 0) {
@@ -193,21 +194,21 @@
 /**
  * Destroys a layering.
  */
-void igraph_i_layering_destroy(igraph_i_layering_t* layering) {
+static void igraph_i_layering_destroy(igraph_i_layering_t* layering) {
     igraph_vector_ptr_destroy_all(&layering->layers);
 }
 
 /**
  * Returns the number of layers in a layering.
  */
-int igraph_i_layering_num_layers(const igraph_i_layering_t* layering) {
+static int igraph_i_layering_num_layers(const igraph_i_layering_t* layering) {
     return (int) igraph_vector_ptr_size(&layering->layers);
 }
 
 /**
  * Returns the list of vertices in a given layer
  */
-igraph_vector_t* igraph_i_layering_get(const igraph_i_layering_t* layering,
+static igraph_vector_t* igraph_i_layering_get(const igraph_i_layering_t* layering,
                                        long int index) {
     return (igraph_vector_t*)VECTOR(layering->layers)[index];
 }
diff --git a/igraph/src/topology.c b/igraph/src/topology.c
--- a/igraph/src/topology.c
+++ b/igraph/src/topology.c
@@ -31,6 +31,7 @@
 #include "igraph_stack.h"
 #include "igraph_attributes.h"
 #include "igraph_structural.h"
+#include "igraph_isoclasses.h"
 #include "config.h"
 
 const unsigned int igraph_i_isoclass_3[] = {  0, 1, 1, 3, 1, 5, 6, 7,
@@ -689,6 +690,9 @@
  * (between 0 and 15), for undirected graph it is only 4. For graphs
  * with four vertices it is 218 (directed) and 11 (undirected).
  *
+ * </para><para>
+ * Multi-edges and self-loops are ignored by this function.
+ *
  * \param graph The graph object.
  * \param isoclass Pointer to an integer, the isomorphism class will
  *        be stored here.
@@ -754,26 +758,31 @@
  * \brief Decides whether two graphs are isomorphic
  *
  * </para><para>
- * From Wikipedia: The graph isomorphism problem or GI problem is the
- * graph theory problem of determining whether, given two graphs G1
- * and G2, it is possible to permute (or relabel) the vertices of one
- * graph so that it is equal to the other. Such a permutation is
- * called a graph isomorphism.</para>
+ * In simple terms, two graphs are isomorphic if they become indistinguishable
+ * from each other once their vertex labels are removed (rendering the vertices
+ * within each graph indistiguishable). More precisely, two graphs are isomorphic
+ * if there is a one-to-one mapping from the vertices of the first one
+ * to the vertices of the second such that it transforms the edge set of the
+ * first graph into the edge set of the second. This mapping is called
+ * an \em isomorphism.
  *
- * <para>This function decides which graph isomorphism algorithm to be
+ * </para><para>Currently, this function supports simple graphs and graphs
+ * with self-loops, but does not support multigraphs.
+ *
+ * </para><para>This function decides which graph isomorphism algorithm to be
  * used based on the input graphs. Right now it does the following:
  * \olist
  * \oli If one graph is directed and the other undirected then an
  *    error is triggered.
+ * \oli If one of the graphs has multi-edges then an error is triggered.
  * \oli If the two graphs does not have the same number of vertices
  *    and edges it returns with \c FALSE.
  * \oli Otherwise, if the graphs have three or four vertices then an O(1)
  *    algorithm is used with precomputed data.
  * \oli Otherwise BLISS is used, see \ref igraph_isomorphic_bliss().
  * \endolist
- * </para>
  *
- * <para> Please call the VF2 and BLISS functions directly if you need
+ * </para><para>Please call the VF2 and BLISS functions directly if you need
  * something more sophisticated, e.g. you need the isomorphic mapping.
  *
  * \param graph1 The first graph.
@@ -793,8 +802,15 @@
     long int nodes1 = igraph_vcount(graph1), nodes2 = igraph_vcount(graph2);
     long int edges1 = igraph_ecount(graph1), edges2 = igraph_ecount(graph2);
     igraph_bool_t dir1 = igraph_is_directed(graph1), dir2 = igraph_is_directed(graph2);
-    igraph_bool_t loop1, loop2;
+    igraph_bool_t loop1, loop2, multi1, multi2;
 
+    IGRAPH_CHECK(igraph_has_multiple(graph1, &multi1));
+    IGRAPH_CHECK(igraph_has_multiple(graph2, &multi2));
+
+    if (multi1 || multi2) {
+        IGRAPH_ERROR("Isomorphism testing is not implemented for multigraphs", IGRAPH_UNIMPLEMENTED);
+    }
+
     if (dir1 != dir2) {
         IGRAPH_ERROR("Cannot compare directed and undirected graphs", IGRAPH_EINVAL);
     } else if (nodes1 != nodes2 || edges1 != edges2) {
@@ -821,7 +837,8 @@
  * Graph isomorphism for 3-4 vertices
  *
  * This function uses precomputed indices to decide isomorphism
- * problems for graphs with only 3 or 4 vertices.
+ * problems for graphs with only 3 or 4 vertices. Multi-edges
+ * and self-loops are ignored by this function.
  * \param graph1 The first input graph.
  * \param graph2 The second input graph. Must have the same
  *   directedness as \p graph1.
@@ -1640,7 +1657,8 @@
     void *arg, *carg;
 } igraph_i_iso_cb_data_t;
 
-igraph_bool_t igraph_i_isocompat_node_cb(const igraph_t *graph1,
+static igraph_bool_t igraph_i_isocompat_node_cb(
+        const igraph_t *graph1,
         const igraph_t *graph2,
         const igraph_integer_t g1_num,
         const igraph_integer_t g2_num,
@@ -1649,7 +1667,8 @@
     return data->node_compat_fn(graph1, graph2, g1_num, g2_num, data->carg);
 }
 
-igraph_bool_t igraph_i_isocompat_edge_cb(const igraph_t *graph1,
+static igraph_bool_t igraph_i_isocompat_edge_cb(
+        const igraph_t *graph1,
         const igraph_t *graph2,
         const igraph_integer_t g1_num,
         const igraph_integer_t g2_num,
@@ -1658,9 +1677,9 @@
     return data->edge_compat_fn(graph1, graph2, g1_num, g2_num, data->carg);
 }
 
-igraph_bool_t igraph_i_isomorphic_vf2(igraph_vector_t *map12,
-                                      igraph_vector_t *map21,
-                                      void *arg) {
+static igraph_bool_t igraph_i_isomorphic_vf2(igraph_vector_t *map12,
+                                             igraph_vector_t *map21,
+                                             void *arg) {
     igraph_i_iso_cb_data_t *data = arg;
     igraph_bool_t *iso = data->arg;
     IGRAPH_UNUSED(map12); IGRAPH_UNUSED(map21);
@@ -1699,11 +1718,11 @@
  * \param map12 Pointer to an initialized vector or a NULL pointer. If not
  *    a NULL pointer then the mapping from \p graph1 to \p graph2 is
  *    stored here. If the graphs are not isomorphic then the vector is
- *    cleared (ie. has zero elements).
+ *    cleared (i.e. has zero elements).
  * \param map21 Pointer to an initialized vector or a NULL pointer. If not
  *    a NULL pointer then the mapping from \p graph2 to \p graph1 is
  *    stored here. If the graphs are not isomorphic then the vector is
- *    cleared (ie. has zero elements).
+ *    cleared (i.e. has zero elements).
  * \param node_compat_fn A pointer to a function of type \ref
  *   igraph_isocompat_t. This function will be called by the algorithm to
  *   determine whether two nodes are compatible.
@@ -1756,7 +1775,8 @@
     return 0;
 }
 
-igraph_bool_t igraph_i_count_isomorphisms_vf2(const igraph_vector_t *map12,
+static igraph_bool_t igraph_i_count_isomorphisms_vf2(
+        const igraph_vector_t *map12,
         const igraph_vector_t *map21,
         void *arg) {
     igraph_i_iso_cb_data_t *data = arg;
@@ -1828,7 +1848,7 @@
     return 0;
 }
 
-void igraph_i_get_isomorphisms_free(igraph_vector_ptr_t *data) {
+static void igraph_i_get_isomorphisms_free(igraph_vector_ptr_t *data) {
     long int i, n = igraph_vector_ptr_size(data);
     for (i = 0; i < n; i++) {
         igraph_vector_t *vec = VECTOR(*data)[i];
@@ -1837,7 +1857,8 @@
     }
 }
 
-igraph_bool_t igraph_i_get_isomorphisms_vf2(const igraph_vector_t *map12,
+static igraph_bool_t igraph_i_get_isomorphisms_vf2(
+        const igraph_vector_t *map12,
         const igraph_vector_t *map21,
         void *arg) {
 
@@ -1883,11 +1904,11 @@
  * \param edge_color2 The edge color vector for the second graph.
  * \param maps Pointer vector. On return it is empty if the input graphs
  *   are no isomorphic. Otherwise it contains pointers to
- *   <type>igraph_vector_t</type> objects, each vector is an
+ *   \ref igraph_vector_t objects, each vector is an
  *   isomorphic mapping of \p graph2 to \p graph1. Please note that
  *   you need to 1) Destroy the vectors via \ref
  *   igraph_vector_destroy(), 2) free them via
- *   <function>free()</function> and then 3) call \ref
+ *   \ref igraph_free() and then 3) call \ref
  *   igraph_vector_ptr_destroy() on the pointer vector to deallocate all
  *   memory when \p maps is no longer needed.
  * \param node_compat_fn A pointer to a function of type \ref
@@ -2473,7 +2494,8 @@
     return 0;
 }
 
-igraph_bool_t igraph_i_subisomorphic_vf2(const igraph_vector_t *map12,
+static igraph_bool_t igraph_i_subisomorphic_vf2(
+        const igraph_vector_t *map12,
         const igraph_vector_t *map21,
         void *arg) {
     igraph_i_iso_cb_data_t *data = arg;
@@ -2560,7 +2582,8 @@
     return 0;
 }
 
-igraph_bool_t igraph_i_count_subisomorphisms_vf2(const igraph_vector_t *map12,
+static igraph_bool_t igraph_i_count_subisomorphisms_vf2(
+        const igraph_vector_t *map12,
         const igraph_vector_t *map21,
         void *arg) {
     igraph_i_iso_cb_data_t *data = arg;
@@ -2635,7 +2658,7 @@
     return 0;
 }
 
-void igraph_i_get_subisomorphisms_free(igraph_vector_ptr_t *data) {
+static void igraph_i_get_subisomorphisms_free(igraph_vector_ptr_t *data) {
     long int i, n = igraph_vector_ptr_size(data);
     for (i = 0; i < n; i++) {
         igraph_vector_t *vec = VECTOR(*data)[i];
@@ -2644,7 +2667,8 @@
     }
 }
 
-igraph_bool_t igraph_i_get_subisomorphisms_vf2(const igraph_vector_t *map12,
+static igraph_bool_t igraph_i_get_subisomorphisms_vf2(
+        const igraph_vector_t *map12,
         const igraph_vector_t *map21,
         void *arg) {
 
@@ -2690,11 +2714,11 @@
  *   edge-colored.
  * \param edge_color2 The edge color vector for the second graph.
  * \param maps Pointer vector. On return it contains pointers to
- *   <type>igraph_vector_t</type> objects, each vector is an
+ *   \ref igraph_vector_t objects, each vector is an
  *   isomorphic mapping of \p graph2 to a subgraph of \p graph1. Please note that
  *   you need to 1) Destroy the vectors via \ref
  *   igraph_vector_destroy(), 2) free them via
- *   <function>free()</function> and then 3) call \ref
+ *   \ref igraph_free() and then 3) call \ref
  *   igraph_vector_ptr_destroy() on the pointer vector to deallocate all
  *   memory when \p maps is no longer needed.
  * \param node_compat_fn A pointer to a function of type \ref
diff --git a/igraph/src/triangles.c b/igraph/src/triangles.c
--- a/igraph/src/triangles.c
+++ b/igraph/src/triangles.c
@@ -394,7 +394,7 @@
 
 /* This removes loop, multiple edges and edges that point
      "backwards" according to the rank vector. */
-
+/* TODO used in scan.c, add prototype to private header */
 int igraph_i_trans4_al_simplify(igraph_adjlist_t *al,
                                 const igraph_vector_int_t *rank) {
     long int i;
diff --git a/igraph/src/type_indexededgelist.c b/igraph/src/type_indexededgelist.c
--- a/igraph/src/type_indexededgelist.c
+++ b/igraph/src/type_indexededgelist.c
@@ -25,13 +25,13 @@
 #include "igraph_interface.h"
 #include "igraph_attributes.h"
 #include "igraph_memory.h"
-#include <string.h>     /* memset & co. */
 #include "config.h"
 
 /* Internal functions */
 
-int igraph_i_create_start(igraph_vector_t *res, igraph_vector_t *el, igraph_vector_t *index,
-                          igraph_integer_t nodes);
+static int igraph_i_create_start(
+        igraph_vector_t *res, igraph_vector_t *el,
+        igraph_vector_t *index, igraph_integer_t nodes);
 
 /**
  * \section about_basic_interface
@@ -829,8 +829,9 @@
  *
  */
 
-int igraph_i_create_start(igraph_vector_t *res, igraph_vector_t *el, igraph_vector_t *iindex,
-                          igraph_integer_t nodes) {
+static int igraph_i_create_start(
+        igraph_vector_t *res, igraph_vector_t *el,
+        igraph_vector_t *iindex, igraph_integer_t nodes) {
 
 # define EDGE(i) (VECTOR(*el)[ (long int) VECTOR(*iindex)[(i)] ])
 
@@ -1018,7 +1019,9 @@
  * will be placed here.
  * \return Error code. The current implementation always returns with
  * success.
- * \sa \ref igraph_get_eid() for the opposite operation.
+ * \sa \ref igraph_get_eid() for the opposite operation;
+ *     \ref IGRAPH_TO(), \ref IGRAPH_FROM() and \ref IGRAPH_OTHER() for
+ *     a faster but non-error-checked version.
  *
  * Added in version 0.2.</para><para>
  *
diff --git a/igraph/src/uninit.c b/igraph/src/uninit.c
--- a/igraph/src/uninit.c
+++ b/igraph/src/uninit.c
@@ -1,3 +1,8 @@
+
+/* Defining _GNU_SOURCE enables the GNU extensions fedisableexcept() and feenableexcept()
+ * when using glibc. It must be defined before any standard headers are included. */
+#define _GNU_SOURCE 1
+#include <fenv.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -253,9 +258,7 @@
 #ifdef __GLIBC__
 #define IEEE0_done
 
-#if ((__GLIBC__>=2) && (__GLIBC_MINOR__>=2))
-#define _GNU_SOURCE 1
-#include <fenv.h>
+#if ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 2)))
  static void
   ieee0(Void)
         
diff --git a/igraph/src/utils.cc b/igraph/src/utils.cc
--- a/igraph/src/utils.cc
+++ b/igraph/src/utils.cc
@@ -23,6 +23,7 @@
 
 namespace bliss {
 
+#if 0
 void
 print_permutation(FILE* const fp,
 		  const unsigned int N,
@@ -88,6 +89,7 @@
     fprintf(fp, ")");
   }
 }
+#endif
 
 bool
 is_permutation(const unsigned int N, const unsigned int* perm)
diff --git a/igraph/src/vector_ptr.c b/igraph/src/vector_ptr.c
--- a/igraph/src/vector_ptr.c
+++ b/igraph/src/vector_ptr.c
@@ -37,12 +37,12 @@
  * (<type>igraph_vector_ptr_t</type>)
  *
  * <para>The \type igraph_vector_ptr_t data type is very similar to
- * the \type igraph_vector_t type, but it stores generic pointers instead of
+ * the \ref igraph_vector_t type, but it stores generic pointers instead of
  * real numbers.</para>
  *
- * <para>This type has the same space complexity as \type
+ * <para>This type has the same space complexity as \ref
  * igraph_vector_t, and most implemented operations work the same way
- * as for \type igraph_vector_t. </para>
+ * as for \ref igraph_vector_t.</para>
  *
  * <para>This type is mostly used to pass to or receive from a set of
  * graphs to some \a igraph functions, such as \ref
@@ -160,7 +160,7 @@
  *
  * If an item destructor is set for this pointer vector, this function will
  * first call the destructor on all elements of the vector and then
- * free all the elements using free(). If an item destructor is not set,
+ * free all the elements using \ref igraph_free(). If an item destructor is not set,
  * the elements will simply be freed.
  *
  * \param v Pointer to the pointer vector whose elements will be freed.
@@ -254,7 +254,7 @@
  * \brief Gives the number of elements in the pointer vector.
  *
  * \param v The pointer vector object.
- * \return The size of the object, ie. the number of pointers stored.
+ * \return The size of the object, i.e. the number of pointers stored.
  *
  * Time complexity: O(1).
  */
@@ -273,7 +273,7 @@
  * </para><para>
  * This function resizes a pointer to vector to zero length. Note that
  * the pointed objects are \em not deallocated, you should call
- * free() on them, or make sure that their allocated memory is freed
+ * \ref igraph_free() on them, or make sure that their allocated memory is freed
  * in some other way, you'll get memory leaks otherwise. If you have
  * set up an item destructor earlier, the destructor will be called
  * on every element.
@@ -537,7 +537,7 @@
  * Sometimes it is necessary to sort the pointers in the vector based on
  * the property of the element being referenced by the pointer. This
  * function allows us to sort the vector based on an arbitrary external
- * comparison function which accepts two \c void* pointers \c p1 and \c p2
+ * comparison function which accepts two <type>void *</type> pointers \c p1 and \c p2
  * and returns an integer less than, equal to or greater than zero if the
  * first argument is considered to be respectively less than, equal to, or
  * greater than the second. \c p1 and \c p2 will point to the pointer in the
diff --git a/igraph/src/walktrap.cpp b/igraph/src/walktrap.cpp
--- a/igraph/src/walktrap.cpp
+++ b/igraph/src/walktrap.cpp
@@ -55,18 +55,12 @@
 
 #include "walktrap_graph.h"
 #include "walktrap_communities.h"
-#include <ctime>
-#include <set>
-#include <cstdlib>
-#include <iostream>
-#include <fstream>
 
 #include "igraph_community.h"
 #include "igraph_components.h"
 #include "igraph_interface.h"
 #include "igraph_interrupt_internal.h"
 
-using namespace std;
 using namespace igraph::walktrap;
 
 /**
@@ -75,12 +69,12 @@
  * This function is the implementation of the Walktrap community
  * finding algorithm, see Pascal Pons, Matthieu Latapy: Computing
  * communities in large networks using random walks,
- * http://arxiv.org/abs/physics/0512106
+ * https://arxiv.org/abs/physics/0512106
  *
  * </para><para>
  * Currently the original C++ implementation is used in igraph,
- * see http://www-rp.lip6.fr/~latapy/PP/walktrap.html
- * I'm grateful to Matthieu Latapy and Pascal Pons for providing this
+ * see https://www-complexnetworks.lip6.fr/~latapy/PP/walktrap.html
+ * We are grateful to Matthieu Latapy and Pascal Pons for providing this
  * source code.
  *
  * </para><para>
diff --git a/igraph/src/walktrap_communities.cpp b/igraph/src/walktrap_communities.cpp
--- a/igraph/src/walktrap_communities.cpp
+++ b/igraph/src/walktrap_communities.cpp
@@ -54,12 +54,11 @@
 // see readme.txt for more details
 
 #include "walktrap_communities.h"
-#include <cstdlib>
-#include <iostream>
-#include <cmath>
+#include "config.h"
 #include <algorithm>
+#include <cmath>
 
-#include "config.h"
+using namespace std;
 
 namespace igraph {
 
diff --git a/igraph/src/walktrap_graph.cpp b/igraph/src/walktrap_graph.cpp
--- a/igraph/src/walktrap_graph.cpp
+++ b/igraph/src/walktrap_graph.cpp
@@ -53,14 +53,10 @@
 //-----------------------------------------------------------------------------
 // see readme.txt for more details
 
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <algorithm>
-#include <cstring>      // strlen
 #include "walktrap_graph.h"
-
 #include "igraph_interface.h"
+#include <algorithm>
+#include <cstring>      // strlen
 
 using namespace std;
 
diff --git a/igraph/src/walktrap_heap.cpp b/igraph/src/walktrap_heap.cpp
--- a/igraph/src/walktrap_heap.cpp
+++ b/igraph/src/walktrap_heap.cpp
@@ -54,11 +54,7 @@
 // see readme.txt for more details
 
 #include "walktrap_heap.h"
-#include <cstdlib>
-#include <iostream>
 
-
-using namespace std;
 using namespace igraph::walktrap;
 
 void Neighbor_heap::move_up(int index) {
diff --git a/igraph/src/zeroin.c b/igraph/src/zeroin.c
--- a/igraph/src/zeroin.c
+++ b/igraph/src/zeroin.c
@@ -79,6 +79,7 @@
  ************************************************************************
  */
 
+#include "igraph_nongraph.h"
 #include "igraph_types.h"
 #include "igraph_interrupt_internal.h"
 
diff --git a/igraph/src/zeta.c b/igraph/src/zeta.c
deleted file mode 100644
--- a/igraph/src/zeta.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/* specfunc/zeta.c
- * 
- * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
- * your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* Author:  G. Jungman */
-
-/* This file was taken from the GNU Scientific Library. Some modifications
- * were done in order to make it independent from the rest of GSL
- */
-
-/*
-#include <config.h>
-#include <gsl/gsl_math.h>
-#include <gsl/gsl_errno.h>
-#include <gsl/gsl_sf_elementary.h>
-#include <gsl/gsl_sf_exp.h>
-#include <gsl/gsl_sf_gamma.h>
-#include <gsl/gsl_sf_pow_int.h>
-#include <gsl/gsl_sf_zeta.h>
-
-#include "error.h"
-
-#include "chebyshev.h"
-#include "cheb_eval.c"
-*/
-
-#include <math.h>
-#include <stdio.h>
-#include "error.h"
-
-/*-*-*-*-*-*-*-*-*-*- From gsl_machine.h -*-*-*-*-*-*-*-*-*-*-*-*-*/
-
-#define GSL_LOG_DBL_MIN   (-7.0839641853226408e+02)
-#define GSL_LOG_DBL_MAX    7.0978271289338397e+02
-#define GSL_DBL_EPSILON        2.2204460492503131e-16
-
-/*-*-*-*-*-*-*-*-*-* From gsl_sf_result.h *-*-*-*-*-*-*-*-*-*-*-*/
-
-struct gsl_sf_result_struct {
-  double val;
-  double err;
-};
-typedef struct gsl_sf_result_struct gsl_sf_result;
-
-/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/
-
-/* coefficients for Maclaurin summation in hzeta()
- * B_{2j}/(2j)!
- */
-static double hzeta_c[15] = {
-  1.00000000000000000000000000000,
-  0.083333333333333333333333333333,
- -0.00138888888888888888888888888889,
-  0.000033068783068783068783068783069,
- -8.2671957671957671957671957672e-07,
-  2.0876756987868098979210090321e-08,
- -5.2841901386874931848476822022e-10,
-  1.3382536530684678832826980975e-11,
- -3.3896802963225828668301953912e-13,
-  8.5860620562778445641359054504e-15,
- -2.1748686985580618730415164239e-16,
-  5.5090028283602295152026526089e-18,
- -1.3954464685812523340707686264e-19,
-  3.5347070396294674716932299778e-21,
- -8.9535174270375468504026113181e-23
-};
-
-/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/
-
-static int gsl_sf_hzeta_e(const double s, const double q, gsl_sf_result * result)
-{
-  /* CHECK_POINTER(result) */
-
-  if(s <= 1.0 || q <= 0.0) {
-	PLFIT_ERROR("s must be larger than 1.0 and q must be larger than zero", PLFIT_EINVAL);
-  }
-  else {
-    const double max_bits = 54.0;
-    const double ln_term0 = -s * log(q);  
-
-    if(ln_term0 < GSL_LOG_DBL_MIN + 1.0) {
-	  PLFIT_ERROR("underflow", PLFIT_UNDRFLOW);
-    }
-    else if(ln_term0 > GSL_LOG_DBL_MAX - 1.0) {
-	  PLFIT_ERROR("overflow", PLFIT_OVERFLOW);
-    }
-    else if((s > max_bits && q < 1.0) || (s > 0.5*max_bits && q < 0.25)) {
-      result->val = pow(q, -s);
-      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);
-      return PLFIT_SUCCESS;
-    }
-    else if(s > 0.5*max_bits && q < 1.0) {
-      const double p1 = pow(q, -s);
-      const double p2 = pow(q/(1.0+q), s);
-      const double p3 = pow(q/(2.0+q), s);
-      result->val = p1 * (1.0 + p2 + p3);
-      result->err = GSL_DBL_EPSILON * (0.5*s + 2.0) * fabs(result->val);
-      return PLFIT_SUCCESS;
-    }
-    else {
-      /* Euler-Maclaurin summation formula 
-       * [Moshier, p. 400, with several typo corrections]
-       */
-      const int jmax = 12;
-      const int kmax = 10;
-      int j, k;
-      const double pmax  = pow(kmax + q, -s);
-      double scp = s;
-      double pcp = pmax / (kmax + q);
-      double ans = pmax*((kmax+q)/(s-1.0) + 0.5);
-
-      for(k=0; k<kmax; k++) {
-        ans += pow(k + q, -s);
-      }
-
-      for(j=0; j<=jmax; j++) {
-        double delta = hzeta_c[j+1] * scp * pcp;
-        ans += delta;
-        if(fabs(delta/ans) < 0.5*GSL_DBL_EPSILON) break;
-        scp *= (s+2*j+1)*(s+2*j+2);
-        pcp /= (kmax + q)*(kmax + q);
-      }
-
-      result->val = ans;
-      result->err = 2.0 * (jmax + 1.0) * GSL_DBL_EPSILON * fabs(ans);
-      return PLFIT_SUCCESS;
-    }
-  }
-}
-
-/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/
-
-double gsl_sf_hzeta(const double s, const double a)
-{
-  gsl_sf_result result;
-  gsl_sf_hzeta_e(s, a, &result);
-  return result.val;
-}
-
diff --git a/include/bytestring.h b/include/bytestring.h
deleted file mode 100644
--- a/include/bytestring.h
+++ /dev/null
@@ -1,111 +0,0 @@
-#ifndef HASKELL_IGRAPH_BYTESTRING
-#define HASKELL_IGRAPH_BYTESTRING
-
-#include "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
diff --git a/include/haskell_attributes.h b/include/haskell_attributes.h
deleted file mode 100644
--- a/include/haskell_attributes.h
+++ /dev/null
@@ -1,218 +0,0 @@
-#ifndef HASKELL_IGRAPH_ATTRIBUTE
-#define HASKELL_IGRAPH_ATTRIBUTE
-
-#include "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
diff --git a/include/haskell_igraph.h b/include/haskell_igraph.h
deleted file mode 100644
--- a/include/haskell_igraph.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef HASKELL_IGRAPH
-#define HASKELL_IGRAPH
-
-#include "igraph.h"
-
-void haskelligraph_init();
-
-#endif
diff --git a/src/IGraph/Algorithms.hs b/src/IGraph/Algorithms.hs
--- a/src/IGraph/Algorithms.hs
+++ b/src/IGraph/Algorithms.hs
@@ -2,7 +2,7 @@
     ( module IGraph.Algorithms.Structure
     , module IGraph.Algorithms.Community
     , module IGraph.Algorithms.Clique
---    , module IGraph.Algorithms.Layout
+    , module IGraph.Algorithms.Layout
     , module IGraph.Algorithms.Motif
     , module IGraph.Algorithms.Generators
     , module IGraph.Algorithms.Isomorphism
@@ -12,7 +12,7 @@
 import IGraph.Algorithms.Structure
 import IGraph.Algorithms.Community
 import IGraph.Algorithms.Clique
---import IGraph.Algorithms.Layout
+import IGraph.Algorithms.Layout
 import IGraph.Algorithms.Motif
 import IGraph.Algorithms.Generators
 import IGraph.Algorithms.Isomorphism
diff --git a/src/IGraph/Algorithms/Centrality.chs b/src/IGraph/Algorithms/Centrality.chs
--- a/src/IGraph/Algorithms/Centrality.chs
+++ b/src/IGraph/Algorithms/Centrality.chs
@@ -4,19 +4,21 @@
     , betweenness
     , eigenvectorCentrality
     , pagerank
+    , hubScore
+    , authorityScore
     ) where
 
 import           Control.Monad
 import           Data.Serialize            (Serialize)
 import Data.List (foldl')
 import           System.IO.Unsafe          (unsafePerformIO)
-import Data.Maybe
 import Data.Singletons (SingI)
 
 import Foreign
 import Foreign.C.Types
 
 import           IGraph
+import IGraph.Internal.C2HS
 {#import IGraph.Internal #}
 {#import IGraph.Internal.Constants #}
 
@@ -140,4 +142,44 @@
     , castPtr `Ptr Vector'
     , castPtr `Ptr Vector'
     , id `Ptr ()'
+    } -> `CInt' void- #}
+
+-- | Kleinberg's hub scores.
+hubScore :: Graph d v e
+         -> Bool -- ^ scale result such that \(\left|max\ centrality\right|=1\)
+         -> ([Double],Double) -- ^ (eigenvector,eigenvalue)
+hubScore graph scale = unsafePerformIO $
+  allocaVector $ \vector ->
+  alloca $ \value ->
+  allocaArpackOpt $ \options -> do
+    igraphHubScore (_graph graph) vector value scale nullPtr options
+    liftM2 (,) (toList vector) (peekFloatConv value)
+{-# INLINE igraphHubScore #-}
+{#fun igraph_hub_score as ^
+    { `IGraph'
+    , castPtr `Ptr Vector'
+    , castPtr `Ptr CDouble'
+    , `Bool'
+    , castPtr `Ptr Vector'
+    , castPtr `Ptr ArpackOpt'
+    } -> `CInt' void- #}
+
+-- | Kleinberg's authority scores.
+authorityScore :: Graph d v e
+               -> Bool -- ^ scale result such that \(\left|max\ centrality\right|=1\)
+               -> ([Double],Double) -- ^ (eigenvector,eigenvalue)
+authorityScore graph scale = unsafePerformIO $
+  allocaVector $ \vector ->
+  alloca $ \value ->
+  allocaArpackOpt $ \options -> do
+    igraphAuthorityScore (_graph graph) vector value scale nullPtr options
+    liftM2 (,) (toList vector) (peekFloatConv value)
+{-# INLINE igraphAuthorityScore #-}
+{#fun igraph_authority_score as ^
+    { `IGraph'
+    , castPtr `Ptr Vector'
+    , castPtr `Ptr CDouble'
+    , `Bool'
+    , castPtr `Ptr Vector'
+    , castPtr `Ptr ArpackOpt'
     } -> `CInt' void- #}
diff --git a/src/IGraph/Algorithms/Clique.chs b/src/IGraph/Algorithms/Clique.chs
--- a/src/IGraph/Algorithms/Clique.chs
+++ b/src/IGraph/Algorithms/Clique.chs
@@ -6,10 +6,7 @@
     , cliqueNumber
     ) where
 
-import Control.Applicative ((<$>))
 import System.IO.Unsafe (unsafePerformIO)
-
-import qualified Foreign.Ptr as C2HSImp
 import Foreign
 
 import IGraph
@@ -18,6 +15,7 @@
 
 #include "haskell_igraph.h"
 
+-- | Find all or some cliques in a graph.
 cliques :: Graph d v e
         -> (Int, Int)  -- ^ Minimum and maximum size of the cliques to be returned.
                        -- No bound will be used if negative or zero
@@ -27,12 +25,16 @@
     (map.map) truncate <$> toLists vptr
 {#fun igraph_cliques as ^ { `IGraph', castPtr `Ptr VectorPtr', `Int', `Int' } -> `CInt' void- #}
 
+-- | Finds the largest clique(s) in a graph.
+-- Time complexity: O(3^(|V|/3)) worst case.
 largestCliques :: Graph d v e -> [[Int]]
 largestCliques gr = unsafePerformIO $ allocaVectorPtr $ \vptr -> do
     igraphLargestCliques (_graph gr) vptr
     (map.map) truncate <$> toLists vptr
 {#fun igraph_largest_cliques as ^ { `IGraph', castPtr `Ptr VectorPtr' } -> `CInt' void- #}
 
+-- | Find all maximal cliques of a graph. Time complexity: O(d(n-d)3^(d/3))
+-- worst case, d is the degeneracy of the graph.
 maximalCliques :: Graph d v e
                -> (Int, Int)  -- ^ Minimum and maximum size of the cliques to be returned.
                               -- No bound will be used if negative or zero
@@ -42,6 +44,9 @@
     (map.map) truncate <$> toLists vpptr
 {#fun igraph_maximal_cliques as ^ { `IGraph', castPtr `Ptr VectorPtr', `Int', `Int' } -> `CInt' void- #}
 
+-- | Find the clique number of the graph. The clique number of a graph is
+-- the size of the largest clique.
+-- Time complexity: O(3^(|V|/3)) worst case.
 cliqueNumber :: Graph d v e -> Int
 cliqueNumber gr = unsafePerformIO $ igraphCliqueNumber $ _graph gr
 {#fun igraph_clique_number as ^
diff --git a/src/IGraph/Algorithms/Community.chs b/src/IGraph/Algorithms/Community.chs
--- a/src/IGraph/Algorithms/Community.chs
+++ b/src/IGraph/Algorithms/Community.chs
@@ -2,11 +2,12 @@
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE DataKinds #-}
 module IGraph.Algorithms.Community
-    ( modularity
-    , findCommunity
+    ( findCommunity
     , CommunityMethod(..)
-    , defaultLeadingEigenvector
-    , defaultSpinglass
+    , leadingEigenvector
+    , spinglass
+    , leiden
+    , modularity
     ) where
 
 import           Data.Function             (on)
@@ -14,37 +15,53 @@
 import Data.List.Ordered (nubSortBy)
 import           Data.Ord (comparing)
 import           System.IO.Unsafe          (unsafePerformIO)
+import           Data.Serialize            (Serialize)
 
 import           Foreign
 import           Foreign.C.Types
 
 import           IGraph
+import           IGraph.Random
 import IGraph.Internal.C2HS
 {#import IGraph.Internal #}
 {#import IGraph.Internal.Constants #}
 
 #include "haskell_igraph.h"
 
-modularity :: Graph d v e
-           -> [[Int]]   -- ^ Communities.
-           -> Maybe [Double] -- ^ Weights
-           -> Double
-modularity gr clusters ws
-    | length nds /= length (concat clusters) = error "Duplicated nodes"
-    | nds /= nodes gr = error "Some nodes were not given community assignments"
-    | otherwise = unsafePerformIO $ withList membership $ \membership' ->
-        withListMaybe ws (igraphModularity (_graph gr) membership')
+-- | Detecting community structure.
+findCommunity :: (Serialize v, Serialize e)
+              => Graph 'U v e
+              -> Maybe (Node -> v -> Double)  -- ^ Function to assign node weights
+              -> Maybe (e -> Double)  -- ^ Function to assign edge weights
+              -> CommunityMethod  -- ^ Community finding algorithms
+              -> Gen
+              -> IO [[Int]]
+findCommunity gr getNodeW getEdgeW method _ = allocaVector $ \result ->
+    withListMaybe ew $ \ew' -> do
+        case method of
+            LeadingEigenvector n -> allocaArpackOpt $ \arpack ->
+                igraphCommunityLeadingEigenvector (_graph gr) ew' nullPtr result
+                                                  n arpack nullPtr False
+                                                  nullPtr nullPtr nullPtr
+                                                  nullFunPtr nullPtr
+            Spinglass{..} -> igraphCommunitySpinglass (_graph gr) ew' nullPtr nullPtr result
+                                     nullPtr _nSpins False _startTemp
+                                     _stopTemp _coolFact
+                                     IgraphSpincommUpdateConfig _gamma
+                                     IgraphSpincommImpOrig 1.0
+            Leiden{..} -> do
+                _ <- withListMaybe nw $ \nw' -> igraphCommunityLeiden
+                    (_graph gr) ew' nw' _resolution _beta False result nullPtr
+                return ()
+        fmap ( map (fst . unzip) . groupBy ((==) `on` snd)
+              . sortBy (comparing snd) . zip [0..] ) $ toList result
   where
-    (membership, nds) = unzip $ nubSortBy (comparing snd) $ concat $
-        zipWith f [0 :: Int ..] clusters
-      where
-        f i xs = zip (repeat i) xs
-{#fun igraph_modularity as ^
-    { `IGraph'
-    , castPtr `Ptr Vector'
-	, alloca- `Double' peekFloatConv*
-	, castPtr `Ptr Vector'
-    } -> `CInt' void- #}
+    ew = case getEdgeW of
+        Nothing -> Nothing
+        Just f -> Just $ map (f . snd) $ labEdges gr
+    nw = case getNodeW of
+        Nothing -> Nothing
+        Just f -> Just $ map (uncurry f) $ labNodes gr
 
 data CommunityMethod =
       LeadingEigenvector
@@ -57,38 +74,44 @@
         , _coolFact  :: Double  -- ^ the cooling factor for the simulated annealing
         , _gamma     :: Double  -- ^ the gamma parameter of the algorithm.
         }
+    | Leiden
+        { _resolution :: Double
+        , _beta :: Double
+        }
 
-defaultLeadingEigenvector :: CommunityMethod
-defaultLeadingEigenvector = LeadingEigenvector 10000
+-- | Default parameters for the leading eigenvector algorithm.
+leadingEigenvector :: CommunityMethod
+leadingEigenvector = LeadingEigenvector 10000
 
-defaultSpinglass :: CommunityMethod
-defaultSpinglass = Spinglass
+-- | Default parameters for the spin-glass algorithm.
+spinglass :: CommunityMethod
+spinglass = Spinglass
     { _nSpins = 25
     , _startTemp = 1.0
     , _stopTemp = 0.01
     , _coolFact = 0.99
     , _gamma = 1.0 }
 
-findCommunity :: Graph 'U v e
-              -> Maybe [Double]   -- ^ node weights
-              -> CommunityMethod  -- ^ Community finding algorithms
-              -> [[Int]]
-findCommunity gr ws method = unsafePerformIO $ allocaVector $ \result ->
-    withListMaybe ws $ \ws' -> do
-        case method of
-            LeadingEigenvector n -> allocaArpackOpt $ \arpack ->
-                igraphCommunityLeadingEigenvector (_graph gr) ws' nullPtr result
-                                                  n arpack nullPtr False
-                                                  nullPtr nullPtr nullPtr
-                                                  nullFunPtr nullPtr
-            Spinglass{..} -> igraphCommunitySpinglass (_graph gr) ws' nullPtr nullPtr result
-                                     nullPtr _nSpins False _startTemp
-                                     _stopTemp _coolFact
-                                     IgraphSpincommUpdateConfig _gamma
-                                     IgraphSpincommImpOrig 1.0
-
-        fmap ( map (fst . unzip) . groupBy ((==) `on` snd)
-              . sortBy (comparing snd) . zip [0..] ) $ toList result
+-- | Default parameters for the leiden algorithm.
+-- 1 / 2m sum_ij (A_ij - gamma n_i n_j)d(s_i, s_j), where
+-- m is the total edge weight,
+-- A_ij is the weight of edge (i, j),
+-- gamma is the so-called resolution parameter,
+-- n_i is the node weight of node i,
+-- s_i is the cluster of node i and
+-- d(x, y) = 1 if and only if x = y and 0 otherwise.
+-- By setting n_i = k_i, the degree of node i, and dividing gamma by 2m,
+-- you effectively obtain an expression for modularity.
+-- Hence, the standard modularity will be optimized when you supply the degrees
+-- as node_weights and by supplying as a resolution parameter 1.0/(2*m), with m the number of edges.
+--
+-- RBConfigurationVertexPartition: supplying the degrees as node weights, and
+-- a resolution parameter 1.0/(2*m), with m the number of edges.
+-- CPM: 
+leiden :: CommunityMethod
+leiden = Leiden
+    { _resolution = 1
+    , _beta = 0.01 }
 
 {#fun igraph_community_spinglass as ^
     { `IGraph'
@@ -124,6 +147,18 @@
     , id `Ptr ()'
     } -> `CInt' void- #}
 
+{#fun igraph_community_leiden as ^
+    { `IGraph'
+    , castPtr `Ptr Vector'
+    , castPtr `Ptr Vector'
+    , `Double'
+    , `Double'
+    , `Bool'
+    , castPtr `Ptr Vector'
+    , alloca- `Int' peekIntConv*
+    , id `Ptr CDouble'
+    } -> `CInt' void- #}
+
 type T = FunPtr ( Ptr ()
                 -> CLong
                 -> CDouble
@@ -132,3 +167,30 @@
                 -> Ptr ()
                 -> Ptr ()
                 -> IO CInt)
+
+-- | Calculate the modularity of a graph with respect to some vertex types.
+modularity :: Serialize e
+           => Graph d v e
+           -> Maybe (e -> Double)  -- ^ Function to assign edge weights
+           -> [[Int]]   -- ^ Communities.
+           -> Double
+modularity gr getEdgeW clusters
+    | length nds /= length (concat clusters) = error "Duplicated nodes"
+    | nds /= nodes gr = error "Some nodes were not given community assignments"
+    | otherwise = unsafePerformIO $ withList membership $ \membership' ->
+        withListMaybe ws (igraphModularity (_graph gr) membership')
+  where
+    (membership, nds) = unzip $ nubSortBy (comparing snd) $ concat $
+        zipWith f [0 :: Int ..] clusters
+      where
+        f i xs = zip (repeat i) xs
+    ws = case getEdgeW of
+        Nothing -> Nothing
+        Just f -> Just $ map (f . snd) $ labEdges gr
+{#fun igraph_modularity as ^
+    { `IGraph'
+    , castPtr `Ptr Vector'
+	, alloca- `Double' peekFloatConv*
+	, castPtr `Ptr Vector'
+    } -> `CInt' void- #}
+
diff --git a/src/IGraph/Algorithms/Generators.chs b/src/IGraph/Algorithms/Generators.chs
--- a/src/IGraph/Algorithms/Generators.chs
+++ b/src/IGraph/Algorithms/Generators.chs
@@ -5,6 +5,7 @@
     ( full
     , star
     , ring
+    , zacharyKarate
     , ErdosRenyiModel(..)
     , erdosRenyiGame
     , degreeSequenceGame
@@ -35,7 +36,7 @@
      -> Bool  -- ^ Whether to include self-edges (loops)
      -> Graph d () ()
 full n hasLoop = unsafePerformIO $ do
-    igraphInit
+    _ <- igraphInit
     gr <- igraphFull n directed hasLoop
     initializeNullAttribute gr
     return $ Graph gr M.empty
@@ -52,7 +53,7 @@
 star :: Int    -- ^ The number of nodes
      -> Graph 'U () ()
 star n = unsafePerformIO $ do
-    igraphInit
+    _ <- igraphInit
     gr <- igraphStar n IgraphStarUndirected 0
     initializeNullAttribute gr
     return $ Graph gr M.empty
@@ -66,7 +67,7 @@
 -- | Creates a ring graph, a one dimensional lattice.
 ring :: Int -> Graph 'U () ()
 ring n = unsafePerformIO $ do
-    igraphInit
+    _ <- igraphInit
     gr <- igraphRing n False False True
     initializeNullAttribute gr
     return $ Graph gr M.empty
@@ -78,6 +79,20 @@
     , `Bool'
     } -> `CInt' void- #}
 
+-- | Zachary's karate club
+zacharyKarate :: Graph 'U () ()
+zacharyKarate = mkGraph (replicate 34 ()) $ map (\(a, b) -> ((a-1,b-1),())) es
+  where
+    es = [ (2,1),(3,1),(3,2),(4,1),(4,2),(4,3),(5,1),(6,1),(7,1),(7,5),(7,6)
+         , (8,1),(8,2),(8,3),(8,4),(9,1),(9,3),(10,3),(11,1),(11,5),(11,6)
+         , (12,1),(13,1),(13,4),(14,1),(14,2),(14,3),(14,4),(17,6),(17,7)
+         , (18,1),(18,2),(20,1),(20,2),(22,1),(22,2),(26,24),(26,25)
+         , (28,3),(28,24),(28,25),(29,3),(30,24),(30,27),(31,2),(31,9)
+         , (32,1),(32,25),(32,26),(32,29),(33,3),(33,9),(33,15),(33,16)
+         , (33,19),(33,21),(33,23),(33,24),(33,30),(33,31),(33,32)
+         , (34,9),(34,10),(34,14),(34,15),(34,16),(34,19),(34,20),(34,21)
+         , (34,23),(34,24),(34,27),(34,28),(34,29),(34,30),(34,31),(34,32),(34,33) ]
+
 data ErdosRenyiModel = GNP Int Double  -- ^ G(n,p) graph, every possible edge is
                                        -- included in the graph with probability p.
                      | GNM Int Int   -- ^ G(n,m) graph, m edges are selected
@@ -90,7 +105,7 @@
                -> Gen
                -> IO (Graph d () ())
 erdosRenyiGame model self _ = do
-    igraphInit
+    _ <- igraphInit
     gr <- case model of
         GNP n p -> igraphErdosRenyiGame IgraphErdosRenyiGnp n p directed self
         GNM n m -> igraphErdosRenyiGame IgraphErdosRenyiGnm n (fromIntegral m)
@@ -112,7 +127,7 @@
                    -> Gen
                    -> IO (Graph 'D () ())
 degreeSequenceGame out_deg in_deg _ = do
-    igraphInit
+    _ <- igraphInit
     withList out_deg $ \out_deg' ->
         withList in_deg $ \in_deg' -> do
             gr <- igraphDegreeSequenceGame out_deg' in_deg' IgraphDegseqSimple
diff --git a/src/IGraph/Algorithms/Isomorphism.chs b/src/IGraph/Algorithms/Isomorphism.chs
--- a/src/IGraph/Algorithms/Isomorphism.chs
+++ b/src/IGraph/Algorithms/Isomorphism.chs
@@ -1,8 +1,8 @@
 {-# LANGUAGE ForeignFunctionInterface #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 module IGraph.Algorithms.Isomorphism
-    ( getSubisomorphisms
-    , isomorphic
+    ( isomorphic
+    , getSubisomorphisms
     , isoclassCreate
     , isoclass3
     , isoclass4
@@ -20,6 +20,17 @@
 
 #include "haskell_igraph.h"
 
+-- | Determine whether two graphs are isomorphic.
+isomorphic :: Graph d v1 e1
+           -> Graph d v2 e2
+           -> Bool
+isomorphic g1 g2 = unsafePerformIO $ alloca $ \ptr -> do
+    _ <- igraphIsomorphic (_graph g1) (_graph g2) ptr
+    x <- peek ptr
+    return (x /= 0)
+{-# INLINE isomorphic #-}
+{#fun igraph_isomorphic as ^ { `IGraph', `IGraph', id `Ptr CInt' } -> `CInt' void- #}
+
 getSubisomorphisms :: Graph d v1 e1  -- ^ graph to be searched in
                    -> Graph d v2 e2   -- ^ smaller graph
                    -> [[Int]]
@@ -43,16 +54,6 @@
     , id `FunPtr (Ptr IGraph -> Ptr IGraph -> CInt -> CInt -> Ptr () -> IO CInt)'
     , id `Ptr ()'
     } -> `CInt' void- #}
-
--- | Determine whether two graphs are isomorphic.
-isomorphic :: Graph d v1 e1
-           -> Graph d v2 e2
-           -> Bool
-isomorphic g1 g2 = unsafePerformIO $ alloca $ \ptr -> do
-    _ <- igraphIsomorphic (_graph g1) (_graph g2) ptr
-    x <- peek ptr
-    return (x /= 0)
-{#fun igraph_isomorphic as ^ { `IGraph', `IGraph', id `Ptr CInt' } -> `CInt' void- #}
 
 -- | Creates a graph from the given isomorphism class.
 -- This function is implemented only for graphs with three or four vertices.
diff --git a/src/IGraph/Algorithms/Layout.chs b/src/IGraph/Algorithms/Layout.chs
new file mode 100644
--- /dev/null
+++ b/src/IGraph/Algorithms/Layout.chs
@@ -0,0 +1,120 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module IGraph.Algorithms.Layout
+    ( layout
+    , LayoutMethod(..)
+    , kamadaKawai
+    , lgl
+    ) where
+
+import           Data.Maybe             (isJust, fromMaybe)
+import           Foreign                (nullPtr)
+import           System.IO.Unsafe          (unsafePerformIO)
+import IGraph
+
+import Foreign
+import IGraph.Random
+{#import IGraph.Internal #}
+
+#include "haskell_igraph.h"
+
+layout :: Graph d v e -> LayoutMethod -> Gen -> [(Double, Double)]
+layout gr method _ = unsafePerformIO $ case method of
+    Random -> allocaMatrix $ \mat -> do
+        igraphLayoutRandom gptr mat
+        getResult mat
+
+    KamadaKawai seed niter kkconst epsilon -> do
+        let f mat = igraphLayoutKamadaKawai gptr mat (isJust seed) niter
+                epsilon (fromMaybe (fromIntegral $ nNodes gr) kkconst) nullPtr
+                nullPtr nullPtr nullPtr nullPtr
+        case seed of
+            Nothing -> allocaMatrix $ \mat -> do
+                f mat
+                getResult mat
+            Just s -> withRowLists ((\(x,y) -> [x,y]) $ unzip s) $ \mat -> do
+                f mat
+                getResult mat
+
+    LGL niter delta area coolexp repulserad cellsize -> allocaMatrix $ \mat -> do
+        igraphLayoutLgl gptr mat niter (delta n) (area n) coolexp
+            (repulserad n) (cellsize n) (-1)
+        getResult mat
+  where
+    n = nNodes gr
+    gptr = _graph gr
+    getResult mat = (\[x, y] -> zip x y) <$> toColumnLists mat
+
+data LayoutMethod =
+    Random 
+  | KamadaKawai { kk_seed      :: Maybe [(Double, Double)]
+                , kk_nIter     :: Int
+                , kk_const     :: Maybe Double  -- ^ The Kamada-Kawai vertex attraction constant
+                , kk_epsilon   :: Double
+                }   -- ^ The Kamada-Kawai algorithm. Time complexity: O(|V|)
+                    -- for each iteration, after an O(|V|^2 log|V|)
+                    -- initialization step. 
+  | LGL { lgl_nIter      :: !Int
+        , lgl_maxdelta   :: (Int -> Double)  -- ^ The maximum length of the move allowed
+        -- for a vertex in a single iteration. A reasonable default is the number of vertices.
+        , lgl_area       :: (Int -> Double)  -- ^ This parameter gives the area
+        -- of the square on which the vertices will be placed. A reasonable
+        -- default value is the number of vertices squared.
+        , lgl_coolexp    :: !Double  -- ^ The cooling exponent. A reasonable default value is 1.5.
+        , lgl_repulserad :: (Int -> Double) -- ^ Determines the radius at which
+        -- vertex-vertex repulsion cancels out attraction of adjacent vertices.
+        -- A reasonable default value is area times the number of vertices.
+        , lgl_cellsize   :: (Int -> Double)
+        }
+
+-- | Default parameters for the Kamada-Kawai algorithm.
+kamadaKawai :: LayoutMethod
+kamadaKawai = KamadaKawai
+    { kk_seed = Nothing
+    , kk_nIter = 10
+    , kk_const = Nothing
+    , kk_epsilon = 0 }
+
+-- | Default parameters for the LGL algorithm.
+lgl :: LayoutMethod
+lgl = LGL
+    { lgl_nIter = 100
+    , lgl_maxdelta = \x -> fromIntegral x
+    , lgl_area = area
+    , lgl_coolexp = 1.5
+    , lgl_repulserad = \x -> fromIntegral x * area x
+    , lgl_cellsize = \x -> area x ** 0.25
+    }
+  where
+    area x = fromIntegral $ x * x
+
+-- | Places the vertices uniform randomly on a plane.
+{#fun igraph_layout_random as ^
+    { `IGraph'
+    , castPtr `Ptr Matrix'
+    } -> `CInt' void- #}
+
+{#fun igraph_layout_kamada_kawai as ^
+    { `IGraph'                    -- ^ Graph
+    , castPtr `Ptr Matrix'        -- ^ Pointer to the result matrix
+    , `Bool'                      -- ^ Whether to use the seed
+    , `Int'                       -- ^ The maximum number of iterations to perform
+    , `Double'                    -- ^ epsilon
+    , `Double'                    -- ^ kkconst
+    , castPtr `Ptr Vector'        -- ^ edges weights
+    , castPtr `Ptr Vector'
+    , castPtr `Ptr Vector'
+    , castPtr `Ptr Vector'
+    , castPtr `Ptr Vector'
+    } -> `CInt' void- #}
+
+{# fun igraph_layout_lgl as ^
+    { `IGraph'
+    , castPtr `Ptr Matrix'
+    , `Int'
+    , `Double'
+    , `Double'
+    , `Double'
+    , `Double'
+    , `Double'
+    , `Int'
+    } -> `CInt' void- #}
diff --git a/src/IGraph/Algorithms/Motif.chs b/src/IGraph/Algorithms/Motif.chs
--- a/src/IGraph/Algorithms/Motif.chs
+++ b/src/IGraph/Algorithms/Motif.chs
@@ -1,7 +1,8 @@
 {-# LANGUAGE ForeignFunctionInterface #-}
 {-# LANGUAGE DataKinds #-}
 module IGraph.Algorithms.Motif
-    ( triad
+    ( dyadCensus
+    , triad
     , triadCensus
     ) where
 
@@ -10,10 +11,26 @@
 import Foreign
 
 import IGraph
+import IGraph.Internal.C2HS
 {#import IGraph.Internal #}
 
 #include "haskell_igraph.h"
 
+-- | Dyad census means classifying each pair of vertices of a directed graph
+-- into three categories: mutual, there is an edge from a to b and also
+-- from b to a; asymmetric, there is an edge either from a to b or
+-- from b to a but not the other way; null, no edges between a and b.
+dyadCensus :: Graph 'D v e -> (Int, Int, Int)
+dyadCensus = unsafePerformIO . igraphDyadCensus . _graph
+{-# INLINE dyadCensus #-}
+
+{#fun igraph_dyad_census as ^
+    { `IGraph'
+    , alloca- `Int' peekIntConv*
+    , alloca- `Int' peekIntConv*
+    , alloca- `Int' peekIntConv*
+    } -> `CInt' void- #}
+
 -- | Every triple of vertices in a directed graph
 -- 003: A, B, C, the empty graph.
 -- 012: A->B, C, a graph with a single directed edge.
@@ -54,16 +71,18 @@
          ]
     make :: [(Int, Int)] -> Graph 'D () ()
     make xs = mkGraph (replicate 3 ()) $ zip xs $ repeat ()
+{-# INLINE triad #-}
 
-triadCensus :: (Ord v, Read v) => Graph d v e -> [Int]
+-- | Calculating the triad census means classifying every triple of vertices
+-- in a directed graph. A triple can be in one of 16 states listed in `triad`.
+triadCensus :: (Ord v, Read v) => Graph 'D v e -> [Int]
 triadCensus gr = unsafePerformIO $ allocaVector $ \result -> do
     igraphTriadCensus (_graph gr) result
     map truncate <$> toList result
-
--- motifsRandesu
-
+{-# INLINE triadCensus #-}
 {#fun igraph_triad_census as ^ { `IGraph'
                                , castPtr `Ptr Vector' } -> `CInt' void- #}
 
+-- motifsRandesu
 {#fun igraph_motifs_randesu as ^ { `IGraph', castPtr `Ptr Vector', `Int'
                                  , castPtr `Ptr Vector' } -> `CInt' void- #}
diff --git a/src/IGraph/Algorithms/Structure.chs b/src/IGraph/Algorithms/Structure.chs
--- a/src/IGraph/Algorithms/Structure.chs
+++ b/src/IGraph/Algorithms/Structure.chs
@@ -3,20 +3,31 @@
 module IGraph.Algorithms.Structure
     ( -- * Shortest Path Related Functions
       shortestPath
+    , averagePathLength
+    , diameter
+    , eccentricity
+    , radius
+      -- * Graph Components
     , inducedSubgraph
     , isConnected
     , isStronglyConnected
     , decompose
+    , articulationPoints
+    , bridges
+      -- * Topological Sorting, Directed Acyclic Graphs
     , isDag
     , topSort
     , topSortUnsafe
+      -- * Other Operations
+    , density
+    , reciprocity
+      -- * Auxiliary types
+    , Neimode(IgraphOut,IgraphIn,IgraphAll) -- not IgraphTotal
     ) where
 
 import           Control.Monad
 import           Data.Serialize            (Serialize)
-import Data.List (foldl')
 import           System.IO.Unsafe          (unsafePerformIO)
-import Data.Maybe
 import Data.Singletons (SingI)
 
 import Foreign
@@ -29,14 +40,6 @@
 
 #include "haskell_igraph.h"
 
-{#fun igraph_shortest_paths as ^
-    { `IGraph'
-    , castPtr `Ptr Matrix'
-    , castPtr %`Ptr VertexSelector'
-    , castPtr %`Ptr VertexSelector'
-    , `Neimode'
-    } -> `CInt' void- #}
-
 -- Calculates and returns a single unweighted shortest path from a given vertex
 -- to another one. If there are more than one shortest paths between the two
 -- vertices, then an arbitrary one is returned.
@@ -53,6 +56,7 @@
         Just f -> withList (map (f . snd) $ labEdges gr) $ \ws ->
             igraphGetShortestPathDijkstra (_graph gr) path nullPtr s t ws IgraphOut
     map truncate <$> toList path
+{-# INLINE shortestPath #-}
 {#fun igraph_get_shortest_path as ^
     { `IGraph'
     , castPtr `Ptr Vector'
@@ -71,13 +75,88 @@
     , `Neimode'
     } -> `CInt' void- #}
 
+-- | Calculates the average shortest path length between all vertex pairs.
+averagePathLength :: SingI d
+                  => Graph d v e
+                  -> Bool     -- ^ if unconnected,
+                              -- include only connected pairs (True)
+                              -- or return number if vertices (False)
+                  -> Double
+averagePathLength graph unconn =
+  cFloatConv $ igraphAveragePathLength (_graph graph) (isDirected graph) unconn
+{-# INLINE igraphAveragePathLength #-}
+{#fun pure igraph_average_path_length as ^
+    { `IGraph'
+    , alloca- `CDouble' peek*
+    , `Bool'
+    , `Bool'
+    } -> `CInt' void- #}
+
+-- | Calculates the diameter of a graph (longest geodesic).
+diameter :: SingI d
+         => Graph d v e
+         -> Bool     -- ^ if unconnected,
+                     -- return largest component diameter (True)
+                     -- or number of vertices (False)
+         -> (Int, [Node])
+diameter graph unconn = unsafePerformIO $
+  alloca $ \pres ->
+  allocaVector $ \path -> do
+    igraphDiameter (_graph graph) pres nullPtr nullPtr path (isDirected graph) unconn
+    liftM2 (,) (peekIntConv pres) (toNodes path)
+{-# INLINE igraphDiameter #-}
+{#fun igraph_diameter as ^
+    { `IGraph'
+    , castPtr `Ptr CInt'
+    , castPtr `Ptr CInt'
+    , castPtr `Ptr CInt'
+    , castPtr `Ptr Vector'
+    , `Bool'
+    , `Bool'
+    } -> `CInt' void- #}
+
+-- | Eccentricity of some vertices.
+eccentricity :: Graph d v e
+             -> Neimode -- ^ 'IgraphOut' to follow edges' direction,
+                        -- 'IgraphIn' to reverse it, 'IgraphAll' to ignore
+             -> [Node]  -- ^ vertices for which to calculate eccentricity
+             -> [Double]
+eccentricity graph mode vids = unsafePerformIO $
+  allocaVector $ \res ->
+  withVerticesList vids $ \vs -> do
+    igraphEccentricity (_graph graph) res vs mode
+    toList res
+{-# INLINE igraphEccentricity #-}
+{#fun igraph_eccentricity as ^
+    { `IGraph'
+    , castPtr `Ptr Vector'
+    , castPtr %`Ptr VertexSelector'
+    , `Neimode'
+    } -> `CInt' void- #}
+
+-- | Radius of a graph.
+radius :: Graph d v e
+       -> Neimode -- ^ 'IgraphOut' to follow edges' direction,
+                  -- 'IgraphIn' to reverse it, 'IgraphAll' to ignore
+       -> Double
+radius graph mode = cFloatConv $ igraphRadius (_graph graph) mode
+{-# INLINE igraphRadius #-}
+{#fun pure igraph_radius as ^
+    { `IGraph'
+    , alloca- `CDouble' peek*
+    , `Neimode'
+    } -> `CInt' void- #}
+
+-- | Creates a subgraph induced by the specified vertices. This function collects
+-- the specified vertices and all edges between them to a new graph.
 inducedSubgraph :: (Ord v, Serialize v)
                 => Graph d v e
-                -> [Int]
+                -> [Node]
                 -> Graph d v e
 inducedSubgraph gr nds = unsafePerformIO $ withVerticesList nds $ \vs ->
     igraphInducedSubgraph (_graph gr) vs IgraphSubgraphCreateFromScratch >>=
         (\g -> return $ Graph g $ mkLabelToId g)
+{-# INLINE inducedSubgraph #-}
 {#fun igraph_induced_subgraph as ^
     { `IGraph'
     , allocaIGraph- `IGraph' addIGraphFinalizer*
@@ -88,10 +167,11 @@
 -- | Decides whether the graph is weakly connected.
 isConnected :: Graph d v e -> Bool
 isConnected gr = igraphIsConnected (_graph gr) IgraphWeak
+{-# INLINE isConnected #-}
 
 isStronglyConnected :: Graph 'D v e -> Bool
 isStronglyConnected gr = igraphIsConnected (_graph gr) IgraphStrong
-
+{-# INLINE isStronglyConnected #-}
 {#fun pure igraph_is_connected as ^
     { `IGraph'
     , alloca- `Bool' peekBool*
@@ -116,7 +196,28 @@
     , `Int'
     } -> `CInt' void- #}
 
+-- | Find the articulation points in a graph.
+articulationPoints :: Graph d v e -> [Node]
+articulationPoints gr = unsafePerformIO $ allocaVector $ \res -> do
+  igraphArticulationPoints (_graph gr) res
+  toNodes res
+{-#INLINE igraphArticulationPoints #-}
+{#fun igraph_articulation_points as ^
+    { `IGraph'
+    , castPtr `Ptr Vector'
+    } -> `CInt' void- #}
 
+-- ^ Find all bridges in a graph.
+bridges :: Graph d v e -> [Edge]
+bridges gr = unsafePerformIO $ allocaVector $ \res -> do
+  igraphBridges (_graph gr) res
+  map (getEdgeByEid gr) <$> toNodes res
+{-# INLINE igraphBridges #-}
+{#fun igraph_bridges as ^
+    { `IGraph'
+    , castPtr `Ptr Vector'
+    } -> `CInt' void- #}
+
 -- | Checks whether a graph is a directed acyclic graph (DAG) or not.
 isDag :: Graph d v e -> Bool
 isDag = igraphIsDag . _graph
@@ -124,11 +225,14 @@
     { `IGraph'
     , alloca- `Bool' peekBool*
     } -> `CInt' void- #}
+{-# INLINE isDag #-}
 
--- | Calculate a possible topological sorting of the graph.
+-- | Calculate a possible topological sorting of the graph. Raise error if the
+-- graph is not acyclic.
 topSort :: Graph d v e -> [Node]
 topSort gr | isDag gr = topSortUnsafe gr
            | otherwise = error "the graph is not acyclic"
+{-# INLINE topSort #-}
 
 -- | Calculate a possible topological sorting of the graph. If the graph is not
 -- acyclic (it has at least one cycle), a partial topological sort is returned.
@@ -138,8 +242,37 @@
     map truncate <$> toList res
   where
     n = nNodes gr
+{-# INLINE topSortUnsafe #-}
 {#fun igraph_topological_sorting as ^
     { `IGraph'
     , castPtr `Ptr Vector'
     , `Neimode'
     } -> `CInt' void- #}
+
+-- | Calculate the density of a graph.
+density :: Graph d v e
+        -> Bool -- ^ whether to include loops
+        -> Double -- ^ the ratio of edges to possible edges
+density gr loops = unsafePerformIO $ alloca $ \res -> do
+  igraphDensity (_graph gr) res loops
+  peek res
+{-# INLINE igraphDensity #-}
+{#fun igraph_density as ^
+    { `IGraph'
+    , castPtr `Ptr Double'
+    , `Bool'
+    } -> `CInt' void -#}
+
+-- | Calculates the reciprocity of a directed graph.
+reciprocity :: Graph d v e
+            -> Bool -- ^ whether to ignore loop edges
+            -> Double -- ^ the proportion of mutual connections
+reciprocity gr ignore_loops = unsafePerformIO $ alloca $ \res -> do
+  igraphReciprocity (_graph gr) res ignore_loops IgraphReciprocityDefault
+  peek res
+{#fun igraph_reciprocity as ^
+    { `IGraph'
+    , castPtr `Ptr Double'
+    , `Bool'
+    , `Reciprocity'
+    } -> `CInt' void -#}
diff --git a/src/IGraph/Internal.chs b/src/IGraph/Internal.chs
--- a/src/IGraph/Internal.chs
+++ b/src/IGraph/Internal.chs
@@ -8,6 +8,7 @@
     , withList
     , withListMaybe
     , toList
+    , toNodes
     , igraphVectorNull
     , igraphVectorFill
     , igraphVectorE
@@ -192,6 +193,10 @@
         igraphVectorCopyTo vec ptr
         map realToFrac <$> peekArray n ptr
 {-# INLINE toList #-}
+
+toNodes :: Ptr Vector -> IO [Node]
+toNodes = fmap (map truncate) . toList
+{-# INLINE toNodes #-}
 
 {#fun igraph_vector_copy_to as ^ { castPtr `Ptr Vector', id `Ptr CDouble' } -> `()' #}
 
diff --git a/src/IGraph/Internal/Constants.chs b/src/IGraph/Internal/Constants.chs
--- a/src/IGraph/Internal/Constants.chs
+++ b/src/IGraph/Internal/Constants.chs
@@ -41,3 +41,6 @@
 
 {#enum igraph_degseq_t as Degseq {underscoreToCase}
     deriving (Show, Read, Eq) #}
+
+{#enum igraph_reciprocity_t as Reciprocity {underscoreToCase}
+    deriving (Show, Read, Eq) #}
diff --git a/src/IGraph/Mutable.hs b/src/IGraph/Mutable.hs
--- a/src/IGraph/Mutable.hs
+++ b/src/IGraph/Mutable.hs
@@ -23,7 +23,7 @@
 import           Data.List                      (foldl', delete)
 import           Data.Primitive.MutVar
 import           Data.Serialize                 (Serialize, encode)
-import           Data.Singletons.Prelude        (Sing, SingI, fromSing, sing)
+import           Data.Singletons (Sing, SingI, fromSing, sing)
 import           Foreign                        hiding (new)
 
 import           IGraph.Internal
diff --git a/src/IGraph/Types.hs b/src/IGraph/Types.hs
--- a/src/IGraph/Types.hs
+++ b/src/IGraph/Types.hs
@@ -13,12 +13,13 @@
 {-# LANGUAGE TypeFamilies           #-}
 {-# LANGUAGE TypeOperators          #-}
 {-# LANGUAGE UndecidableInstances   #-}
+{-# LANGUAGE StandaloneKindSignatures #-}
 
 module IGraph.Types where
 
 import           Data.Serialize          (Serialize)
-import           Data.Singletons.Prelude
 import           Data.Singletons.TH
+import Prelude.Singletons
 import           GHC.Generics            (Generic)
 
 $(singletons [d|
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,4 +1,4 @@
 packages:
     - '.'
 
-resolver: lts-15.0
+resolver: lts-24.2
diff --git a/tests/Test/Algorithms.hs b/tests/Test/Algorithms.hs
--- a/tests/Test/Algorithms.hs
+++ b/tests/Test/Algorithms.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeApplications #-}
 module Test.Algorithms
     ( tests
     ) where
@@ -6,6 +7,7 @@
 import           Control.Arrow
 import           Control.Monad.ST
 import           Data.List
+import Control.Monad
 import qualified Data.Matrix.Unboxed as M
 import           Test.Tasty
 import           Test.Tasty.HUnit
@@ -20,9 +22,19 @@
     [ graphIsomorphism
     , motifTest
     , cliqueTest
+    , averagePathTest
+    , diameterTest
+    , eccentricityTest
+    , radiusTest
     , subGraphs
     , decomposeTest
+    , articulationTest
+    , bridgeTest
+    , communityTest
     , pagerankTest
+    , kleinbergTest
+    , densityTest
+    , reciprocityTest
     ]
 
 graphIsomorphism :: TestTree
@@ -55,6 +67,37 @@
         [2,3,4], [2,4,5] ]
     c4 = [[1, 2, 3, 4], [1, 2, 4, 5]]
 
+averagePathTest :: TestTree
+averagePathTest = testGroup "Average path lengths"
+    [ testCase "clique" $ averagePathLength (full @'U 10 False) True @?= 1
+    , testCase "star" $ averagePathLength (star 10) True @?~ 1.8
+    , testCase "ring" $ averagePathLength (ring 11) True @?= 3
+    ]
+
+diameterTest :: TestTree
+diameterTest = testGroup "Diameters"
+    [ testCase "clique" $ fst (diameter (full @'U 10 False) True)  @?= 1
+    , testCase "star"   $ fst (diameter (star 10)          False) @?= 2
+    , testCase "ring"   $ fst (diameter (ring 10)          False) @?= 5
+    ]
+
+eccentricityTest :: TestTree
+eccentricityTest = testGroup "Eccentricity"
+    [ testCase "clique" $
+        eccentricity (full @'U 10 False) IgraphAll [0..9] @?= replicate 10 1
+    , testCase "star" $
+        eccentricity (star 10) IgraphAll [0..9] @?= (1 : replicate 9 2)
+    , testCase "ring" $
+        eccentricity (ring 10) IgraphAll [0..9] @?= replicate 10 5
+    ]
+
+radiusTest :: TestTree
+radiusTest = testGroup "Radius"
+    [ testCase "clique" $ radius (full @'U 10 False) IgraphAll @?= 1
+    , testCase "star" $ radius (star 10) IgraphAll @?= 1
+    , testCase "ring" $ radius (ring 10) IgraphAll @?= 5
+    ]
+
 subGraphs :: TestTree
 subGraphs = testGroup "generate induced subgraphs"
     [ testCase "" $ test case1 ]
@@ -83,15 +126,71 @@
     ]
   where
     es = [ (0,1), (1,2), (2,0)
-		 , (3,4), (4,5), (5,6)
-		 , (8,9), (9,10) ]
+         , (3,4), (4,5), (5,6)
+         , (8,9), (9,10) ]
     gr = mkGraph (replicate 11 ()) $ zip es $ repeat () :: Graph 'U () ()
 
+articulationTest :: TestTree
+articulationTest = testCase "Articulation points" $
+  articulationPoints (star 3) @?= [0]
+
+bridgeTest :: TestTree
+bridgeTest = testCase "Bridges" $ edgeLab g <$> bridges g @?= ["bridge"]
+  where g = fromLabeledEdges @'U
+            [ (("a","b"),"ab") , (("b","c"),"bc") , (("c","a"),"ca")
+            , (("i","j"),"ij") , (("j","k"),"jk") , (("k","i"),"ki")
+            , (("a","i"),"bridge")
+            ]
+
+communityTest :: TestTree
+communityTest = testGroup "Community"
+    [ consistency, consistency2 ]
+  where
+    consistency = testCase "Consistency" $ do
+        rs <- replicateM 50 $ withSeed 134 $ findCommunity zacharyKarate Nothing Nothing spinglass
+        all (== head rs) rs @=? True
+    consistency2 = testCase "Consistency -- leiden" $ do
+        rs <- replicateM 50 $ withSeed 234 $ findCommunity zacharyKarate Nothing Nothing leiden
+        True @=? all (== head rs) rs
+    gr = mkGraph (replicate 10 ()) $ map (\(i,j) -> ((i,j),()))
+        [ (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4)
+        , (3, 4), (5, 6), (5, 7), (5, 8), (5, 9), (6, 7), (6, 8), (6, 9), (7, 8)
+        , (7, 9), (8, 9), (0, 5) ] :: Graph 'U () ()
+
 pagerankTest :: TestTree
 pagerankTest = testGroup "PageRank"
-    [ testCase "case 1" $ ranks @=? ranks' ]
+    [ consistency
+    , testCase "case 1" $ ranks @=? ranks' ]
   where
+    consistency = testCase "Consistency" $ 
+        pagerank gr 0.85 Nothing Nothing @=?
+        pagerank gr 0.85 Nothing Nothing
     gr = star 11
     ranks = [0.47,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05]
     ranks' = map ((/100) . fromIntegral . round. (*100)) $
         pagerank gr 0.85 Nothing Nothing
+
+kleinbergTest :: TestTree
+kleinbergTest = testGroup "Kleinberg"
+    [ testCase "Hub score" $
+        fst (hubScore (full @'U 16 False) True) @?= replicate 16 1
+    , testCase "Authority score" $
+        fst (authorityScore (ring 4) False) @?= replicate 4 0.5
+    ]
+
+densityTest :: TestTree
+densityTest = testGroup "Density"
+    [ testCase "clique" $ density (full @'U 16 False) False @?= 1
+    , testCase "ring" $ density (ring 9) False @?= 1/4
+    ]
+
+reciprocityTest :: TestTree
+reciprocityTest = testGroup "Reciprocity"
+    [ testCase "clique" $ reciprocity (full @'D 10 False) False @?= 1
+    , testCase "ring" $ reciprocity g False @?= 0
+    ]
+  where g = fromLabeledEdges @'D [(("a","b"),()),(("b","c"),()),(("c","a"),())]
+
+-- approximate equality helper
+(@?~) :: (Ord n,Fractional n) => n -> n -> Assertion
+a @?~ b = assertBool "" $ abs (b-a) < 1/65536
